当试图了解与this question相关的编译器行为(gcc和clang)时,我只是不明白为什么在gcc和clang之间的第三种情况(如下所示)有所不同。关于这种转换API(尤其是引用情况)的正确性,问题是而不是
您能否帮助我了解这种情况下的预期行为(从C++标准的 Angular 来看)?
编辑:如注释中所述,只有从-std = c++ 17才能在clang中观察到此行为。在此之前,引用转换与gcc一样。
EDIT2 :请注意,作为隐式this参数的gcc正确行为“似乎”不是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;
}
DEMO HERE
谢谢你的帮助。

最佳答案

这是尝试从到目前为止的研究中回答我自己的问题,并在评论中提供有益的帮助。
非常欢迎评论中的任何评论以改善答案。
答案与this answerthat one密切相关,因此问题本身可能是重复的。
海湾合作委员会案

  • 这是直接初始化(SInternal si(s);)的情况。这种情况属于dcl.init:


  • 结果:考虑SInternal()SInternal(const SInternal&)并选择SInternal(const SInternal&)
  • 引用必须绑定(bind)到SInternal(SInternal是要初始化的引用的类型,S是初始化器表达式的类型)。这种情况属于over.match.ref:
    ...
    考虑S的转换函数及其基类。那些未隐藏在S中且产生类型“对cv2 T2的左值引用”(在初始化对函数的左值引用或右值引用时)或“cv2 T2”或“对cv2 T2的右值引用”的非显式转换函数将右值引用或左值引用初始化为函数),其中“cv1 T”与“cv2 T2”是引用兼容的([dcl.init.ref])
    ...

  • 结果:候选函数为operator SInternal() constoperator SInternal& ()
  • 重载分辨率。此案例属于[over.match.ref](此案例属于over.ics.rank):

  • 结果:选择了operator SInternal& (),因为隐式this参数不是常量。
  • 最终结果伪代码: SInternal(operator SInternal& ())

  • lang盒
    如其他文章所述,该行为似乎与CWG 2327有关。
    如果这是此类行为的编译器实现,则考虑将转换函数用于直接初始化,并选择operator SInternal () const
    最后一点是转换运算符的实现。如果SInternal复制ctor变得微不足道,则不会调用复制构造函数。如果定义了空副本构造函数,则将其称为(DEMO)。
    这是由于SInternal变为TriviallyCopyable,因此编译器从中获利,可以使用寄存器进行复制。如果您用更多数据成员(例如SInternal)填充char arr[32];,它将最终使用memcpy

    关于c++ - 用户定义的转换运算符在clang和gcc之间重载选择的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63618919/

    10-11 22:46