当试图了解与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 answer和that one密切相关,因此问题本身可能是重复的。
海湾合作委员会案
SInternal si(s);
)的情况。这种情况属于dcl.init:结果:考虑
SInternal()
和SInternal(const SInternal&)
并选择SInternal(const SInternal&)
SInternal
是要初始化的引用的类型,S
是初始化器表达式的类型)。这种情况属于over.match.ref:...
考虑S的转换函数及其基类。那些未隐藏在S中且产生类型“对cv2 T2的左值引用”(在初始化对函数的左值引用或右值引用时)或“cv2 T2”或“对cv2 T2的右值引用”的非显式转换函数将右值引用或左值引用初始化为函数),其中“cv1 T”与“cv2 T2”是引用兼容的([dcl.init.ref])
...
结果:候选函数为
operator SInternal() const
和operator SInternal& ()
结果:选择了
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/