我有一些像这样的代码
struct B
{
B() {}
B(int v) {}
};
struct A
{
operator int() const { return 1; }
operator B() const { return B(); }
};
int main()
{
A a;
static_cast<B>(a); // Error here
a.operator B(); // This is OK
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它会产生这样的编译错误:
main.cpp: In function ‘int main()’:
main.cpp:16:21: error: call of overloaded ‘B(A&)’ is ambiguous
static_cast<B>(a);
^
main.cpp:4:5: note: candidate: B::B(int)
B(int v) {}
^
main.cpp:1:8: note: candidate: constexpr B::B(const B&)
struct B
^
main.cpp:1:8: note: candidate: constexpr B::B(B&&)
Run Code Online (Sandbox Code Playgroud)
我不问如何解决这个问题.只想了解为什么编译器不接受它?从我的POV static_cast<B>(a)是相同的,a.operator B()但似乎compilator读取它不同.
更新:
这种行为发生在c ++ 17之前.使用c ++ 17,此代码不会产生任何编译错误.
根据 N3797 [expr.static.cast] 第 4 段:
对于某些发明的临时变量(8.5),如果声明格式良好,则
e可以T使用以下static_cast形式将表达式显式转换为类型。这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。static_cast<T>(e)T t(e);t
该表达式执行初始化程序中static_cast<B>(a)类型的临时变量的直接初始化。那么 N3797 [dcl.init] 第 17 段中的以下项目符号适用:Ba
如果初始化是直接初始化,或者是复制初始化,其中源类型的 cv 未限定版本与目标类是同一类或目标类的派生类,则考虑构造函数。枚举适用的构造函数(13.3.1.3),并通过重载决议选择最好的构造函数(13.3)。调用如此选择的构造函数来初始化对象,并使用初始化表达式或表达式列表作为其参数。如果没有应用构造函数,或者重载决策不明确,则初始化格式错误。
“适用的构造函数”由 N3797 [over.match.ctor] 定义:
对于直接初始化,候选函数是被初始化对象的类的所有构造函数。
因此,所有三个构造函数:B::B(int)、B::B(const B&)、B::B(B&&)都是重载决议期间的候选构造函数。然后比较三个相应的隐式转换序列:A->int、A->const B&、 。A->B&&因此,A->int可与其他两个区分开来,因为不满足 N3797 [over.ics.rank] 第 3 段中以下项目符号的条件:
如果用户定义的转换序列
U1包含相同的用户定义的转换函数或构造函数,或者它们在聚合初始化中初始化相同的类,并且在任一情况下都是 U1 的第二个标准转换序列,则用户定义的转换序列是比另一个用户定义的转换序列更好的转换序列优于 的第二个标准转换序列。U2U2
此外,N3797 [over.match.best] 第 1 段中没有适用确定最佳可行函数的特殊规则,因此重载决策不明确,从而导致编译器错误。
上面的推论也成立,所以这是一个编译器错误(目前)。由于CWG 242 ,[expr.static.cast] 第 4 段的措辞已发生变化,但这并不影响我们的结论。
请注意,保证复制省略在这里不适用,因为它不是来自相同类型的纯右值的初始化。
已经有关于在这种直接初始化情况下添加保证复制省略的讨论,所以也许选择的行为a.operator B()将来会是合法的。
| 归档时间: |
|
| 查看次数: |
515 次 |
| 最近记录: |