此程序/std:c++20
1下的no longer compiles,从MSVC 19.29(VS16.11)开始:
struct X {
X(int) {}
operator int() { return {}; }
};
int main() {
true ? 42 : X(1729);
}
字符串
编译器诊断读取:
error C2445: result type of conditional expression is ambiguous: types 'int' and 'X' can be converted to multiple common types
note: could be 'int'
note: or 'X'
型
这似乎是合理的,因为X
实现了一个转换构造函数,可以隐式地从int
转换为X
,以及一个用户定义的转换函数,可以隐式地从X
转换为int
。
在这一点上,Maven们似乎也达成了一致:
GCC的
<source>:7:10: error: operands to '?:' have different types 'int' and 'X'
7 | true ? 42 : X(1729);
| ~~~~~^~~~~~~~~~~~~~
<source>:7:10: note: and each type can be converted to the other
型
Clang的
<source>:7:10: error: conditional expression is ambiguous; 'int' can be converted to 'X' and vice versa
7 | true ? 42 : X(1729);
| ^ ~~ ~~~~~~~
型
提问
这是一个有效的C++程序吗?如果不是,为什么?
奖励问题
对库作者的指导是什么2?关于构造的explicit
是否足够?如果是,为什么?
1* 这用于在previous versions中编译,并且在使用/permissive
compiler option时仍然如此。
2*X
与MFC的CStringT
类模板具有相同的属性。*
1条答案
按热度按时间voj3qocg1#
是的,这在每个[expr.cond]/4中是不明确的,因为可以从
:
操作数到另一个操作数的类型形成隐式转换序列。没有对这些转换序列应用排名。C++20之前的MSVC隐式地使用
/permissive
,这使得一些行为不符合标准,这似乎也发生在这里。这个特殊的问题可以通过使构造函数或转换函数
explicit
来避免,在这种情况下,它不能在隐式转换序列中使用。一般来说,如果没有充分的理由证明一个等价的普通成员函数调用不足以满足要求,我建议避免使用转换函数。
我还建议将构造函数和转换函数都设置为
explicit
,除非你想让用户把int
传递给一个接受X
的函数,或者把X
传递给一个需要int
的函数,如果用户假设这个函数接受另一个类型,那么这是有意义的。和字符串类型。如果构造函数和转换函数都是
explicit
,那么条件运算符将再次失败,这一次是因为两个转换序列都不能形成。但我认为这很好。字符串和int
是不等价的。用户应该明确说明他们想要哪种类型。