Visual Studio 从MSVC 19.29(VS16.11)开始的条件运算符表达式问题C2445

ryevplcw  于 10个月前  发布在  其他
关注(0)|答案(1)|浏览(128)

此程序/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类模板具有相同的属性。*

voj3qocg

voj3qocg1#

是的,这在每个[expr.cond]/4中是不明确的,因为可以从:操作数到另一个操作数的类型形成隐式转换序列。没有对这些转换序列应用排名。
C++20之前的MSVC隐式地使用/permissive,这使得一些行为不符合标准,这似乎也发生在这里。
这个特殊的问题可以通过使构造函数或转换函数explicit来避免,在这种情况下,它不能在隐式转换序列中使用。
一般来说,如果没有充分的理由证明一个等价的普通成员函数调用不足以满足要求,我建议避免使用转换函数。
我还建议将构造函数和转换函数都设置为explicit,除非你想让用户把int传递给一个接受X的函数,或者把X传递给一个需要int的函数,如果用户假设这个函数接受另一个类型,那么这是有意义的。和字符串类型。
如果构造函数和转换函数都是explicit,那么条件运算符将再次失败,这一次是因为两个转换序列都不能形成。但我认为这很好。字符串和int是不等价的。用户应该明确说明他们想要哪种类型。

相关问题