条件运算符:不同编译器隐式转换序列不一致问题
条件运算符中基类与派生类对象的编译行为疑问
这是问题《conditional operator expression with base and const derived class doesn't compile, why?》的后续,核心场景为cond ? [cv] T1() : [cv] T2(),其中T2公有继承自T1。
在推导该表达式的类型时,似乎需要依赖派生类对象到基类对象的隐式转换序列,但cppreference的隐式转换规则仅覆盖了派生类指针/引用到基类指针/引用的转换,未明确提及对象本身的转换逻辑。
原问题使用的类型十分简单:
struct X {}; struct Y : X {};
这类类型会生成隐式默认的移动和拷贝构造函数,可能构成隐式转换序列。为验证该假设,我们显式声明这些构造函数以打破转换序列:
#include <iostream> struct X { X() = default; explicit X(X const &) { std::cout << "copy to base\n"; } explicit X(X &&) { std::cout << "move to base\n"; } virtual ~X() = default; }; struct Y : X { Y() = default; Y(Y const &y) : X(y) { std::cout << "copy to derived\n"; } Y(Y &&) { std::cout << "move to derived\n"; } virtual ~Y() = default; }; int main() { true ? Y() : X(); }
测试不同explicit关键字组合后,得到如下结果:
| explicit修饰情况 | gcc | clang | msvc |
|---|---|---|---|
| 无 | move to base | move to base | move to base |
| 仅修饰移动构造 | move to base(预期为copy) | copy to base | move to base(预期为copy) |
| 仅修饰拷贝构造 | move to base | move to base | move to base |
| 两者都修饰 | move to base(预期为error) | error | error |
我的预期逻辑是:若基类存在隐式移动构造函数,则使用它构成转换序列;否则尝试使用隐式拷贝构造函数;若两者都不存在,则无合法的隐式转换序列。
为何不同编译器的输出存在差异,且部分结果与预期不符?
注:条件运算符的使用对问题至关重要,替换为函数调用时结果更符合预期(除MSVC外):
void foo(X) {}; int main() { foo(Y()); }
此场景下仅MSVC行为异常,始终使用移动运算符,推测是MSVC的bug。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

