当前位置: 首页 > 知识库问答 >
问题:

clang和gcc用户自定义转换运算符重载选择的区别

慕意致
2023-03-14

在试图获得与这个问题相关的编译器行为(gcc和clang)的一些见解时,我只是不明白为什么gcc和clang之间的第三种情况(如下所示)有所不同。问题不是关于这样一个转换API的正确性(尤其是参考案例)。

你能帮我理解一下这个场景中的预期行为吗(从c标准的角度来看)?

编辑:如评论中所述,这种行为仅在clang中从-std=c 17中观察到。在此之前,引用转换与gcc中一样使用。

EDIT2:注意,正确的行为“似乎”是gcc,因为隐式< code>this参数不是< code>const,因此非const重载是首选的...

下面是示例代码:

struct SInternal {
    SInternal() = default;
    SInternal(const SInternal&) {
        std::cout << "copy ctor" << std::endl;
    }
    int uuid{0};
};

struct S {
 SInternal s;

 S() = default;

 operator SInternal() const {
     std::cout << "copy conversion" << std::endl;
     return s;
 }

 operator SInternal& () {
     std::cout << "ref conversion" << std::endl;
     return s;
 }
};

int main() {
    S s;
    const S s2;
    // 1-
    //SInternal si = s; // no ambiguity, ref conversion
    //SInternal si = s2; // no ambiguity, copy conversion
    // 2-
    // SInternal& si = s; // no ambiguity, ref conversion
    // SInternal& si = s2; // no viable conversion operator SInternal& not const
    // Case 3- WHAT IS THE CORRECT EXPECTED BEHAVIOR HERE?
    SInternal si(s); // no ambiguity but clang uses copy conversion
                     // while gcc uses ref conversion
    //SInternal si(s2); // no ambiguity, copy conversion
    // 4-
    //SInternal si = std::move(s); // no ambiguity ref conversion

    std::cout << "test " << si.uuid << std::endl;
}

在这里演示。

感谢您的帮助。

共有1个答案

吴康平
2023-03-14

以下是我从目前的研究中试图回答我自己的问题,并在评论中提供了善意的帮助。

欢迎评论中的任何评论来改进答案。

答案与这个答案和那个答案密切相关,因此问题本身可能是重复的。

  1. 这是直接初始化 (S内部 si;) 的一种情况。本案属于以下情况:

否则,如果初始化是直接初始化,或者是复制初始化,其中源类型的cv非限定版本与目标类的类或其派生类相同,则考虑构造函数。枚举适用的构造函数([over.match.ctor]),并通过重载解析选择最佳构造函数。调用所选的构造函数来初始化对象,并将初始值设定项表达式或表达式列表作为其参数。如果没有应用构造函数,或者重载解析不明确,则初始化格式不正确。

结果:S内部()S内部(const S内部

引用必须绑定到SInternal(< code > SInternal 是正在初始化的引用的类型,< code>S是初始值设定项表达式的类型)。这个案子属于over.match.ref:

…考虑了S及其基类的转换函数。那些不隐藏在S中的非显式转换函数,并产生类型“lvalue reference to cv2 T2”(当初始化lvalue引用或函数的rvalue引用时)或“cv2 T1”或“rvalue reforence to cv 2 T2)(当初始化函数的rvalize引用或lvalue reference时),其中“cv1 T”与“cv2T2”的引用兼容([dcl.init.ref]),是候选函数。。。

结果:候选函数为operator SInternal()constoperator SInternal

结果:运算符S内部

该行为似乎与其他帖子中解释的CWG 2327有关。

如果这是此类行为的编译器实现,则考虑直接初始化转换函数,并选择运算符 SInternal () const

最后一点是转换操作符的实现。如果< code>SInternal copy ctor很简单,则不会调用copy构造函数。如果定义了一个空的复制构造函数,那么就调用它(DEMO)。

这是因为SInternal变为“普通可复制”,因此编译器利用它来使用寄存器进行复制。如果您用更多的数据成员填充SInternal(例如char arr[32];>),它最终将使用

 类似资料:
  • 给定以下代码(在wandbox上): 和下列编译器选项: cppreference似乎建议语法应该触发显式转换。

  • 自定义运算符 struct Vector2D { var x = 0.0 var y = 0.0 } infix operator +++ extension Vector2D { static func +++ (left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left

  • VC: (34):错误C2593:'运算符='是含糊不清的 (26):注意:可能是测试 (25):注:或“测试” (69):注意:当试图匹配参数列表时'(测试,包装器)' ======生成:0成功,1失败,0最新,0跳过========== 叮当声: : 34:7:错误:重载运算符=的使用不明确(操作数类型为Test和typename std::remove_reference 测试=标准::移动

  • 本文向大家介绍浅谈C++类型转化(运算符重载函数)和基本运算符重载(自增自减),包括了浅谈C++类型转化(运算符重载函数)和基本运算符重载(自增自减)的使用技巧和注意事项,需要的朋友参考一下 类型转化(运算符重载函数) 用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。在C++提供

  • 我有带转换操作符的简单代码,似乎所有的编译器都给出不同的结果,我很好奇哪个编译器是正确的?我也尝试了不同的组合,但以下是最有趣的。代码是使用C 11标志编译的,但是在C 03中也可能观察到相同的行为。 叮当声-3.6: g -4.9: msvc 2014年CTP: 删除后: msvc编译: 此外,在移除const in后 叮当声-3.6: g -4.9: msvc 2014年CTP:

  • 我在C#中定义了一个类(称为类A),并为它重载了一些算术运算符。让我们关注加法运算符(尽管我希望其他运算符的行为类似)。我已经设置了类A,这样我就可以向它添加标量(即单个Double值),我可以将它添加到标量中,或者我可以将A的两个实例一起添加。 所以在C#中,我用三个不同的签名重载了“”运算符。显式签名是: 一个双人间 < li >双A 答:答:答 当我在PowerShell中使用该类时,它只识