C++ 为什么不是';不要叫‘A(c)’总的来说,这是不明确的吗?
为什么调用C++ 为什么不是';不要叫‘A(c)’总的来说,这是不明确的吗?,c++,initialization,language-lawyer,ambiguous,c++17,C++,Initialization,Language Lawyer,Ambiguous,C++17,为什么调用A(c)不明确 struct C; struct A { A() { std::cout << "default ctor A" << '\n'; } A(const A&) { std::cout << "copy A" << '\n'; } A(C&) { std::cout << "ctor A(C)" << '\n'; }; }; struct C {
A(c)main()中的code>不明确
struct C;
struct A {
A() { std::cout << "default ctor A" << '\n'; }
A(const A&) { std::cout << "copy A" << '\n'; }
A(C&) { std::cout << "ctor A(C)" << '\n'; };
};
struct C {
C() { std::cout << "default ctor C" << '\n'; }
operator A() { std::cout << "C::operator A()" << '\n'; return A(); };
};
int main()
{
C c;
A a(c);
}
如果我们注释掉构造函数A::A(C&),代码将打印:
default ctor C
C::operator A()
default ctor A
copy A
copy A
如果有这种情况,重载解析过程的目标是确定如何将C
转换为A
,那么它确实是不明确的,因为可以使用转换构造函数或转换函数:
void f(A);
f(c);
但是,这与以下情况不同:
A a(c);
这里,重载解析用于确定调用A
的哪个构造函数,因此它选择参数类型与参数类型完全匹配的构造函数
C++14中的标准引用是[over.match.ctor]/1:
类类型的对象直接初始化(8.5)或从相同或
作为派生类类型(8.5),重载解析选择构造函数。对于直接初始化,候选
函数是被初始化对象类的所有构造函数。对于复制初始化
候选函数是该类的所有转换构造函数(12.3.1)。参数列表是
初始值设定项的表达式列表或赋值表达式
为什么要“模棱两可”?所谓的歧义在哪里?它是基于操作的优先级。@WakeupBrazil其中一个直接调用构造函数,另一个首先调用转换运算符,然后调用构造函数。一个操作优先于两个操作,这一点并不奇怪。通过逻辑将char
传递到void func(int);void func(char)代码>也应该是不明确的。一个是“精确匹配”,另一个是“转换”。前者是严格意义上更好的重载,但声明中的表达式a(c)
不一样,也不是a
@WakeupBrazil类型的派生类:你在说什么A
有一个构造函数,它将C
作为参数。而C
与表达式C
@nicolabolas的类型相同,我的印象是,[over.match.ctor]/1中来自相同或派生类类型(8.5)
表达式的句子将适用于两种情况,直接初始化和复制初始化。这就解释了我上面的评论。但现在,更仔细地看一下引用的段落,我可以看到所提及的句子只适用于复制初始化。@Nicolas,但我仍然不明白这段话如何解释A::A(C&)
和C::operator A()
没有歧义。@WakeupBrazil:“候选函数是被初始化对象类的所有构造函数”C::operator A()
不是A
的构造函数之一,因此它不是候选函数集的一部分。因此不存在歧义。
A a(c);