C++ 编译器认为;A(A)段“;暂时接受右值?
我有这个密码C++ 编译器认为;A(A)段“;暂时接受右值?,c++,c++11,overload-resolution,list-initialization,C++,C++11,Overload Resolution,List Initialization,我有这个密码 struct A { A(); A(A&); }; struct B { B(const A&); }; void f(A); void f(B); int main() { f(A()); } 令我惊讶的是,GCC和Clang没有做到这一点。例如,克朗说 Compilation finished with errors: source.cpp:8:10: error: no matching constructor for initiali
struct A { A(); A(A&); };
struct B { B(const A&); };
void f(A);
void f(B);
int main() {
f(A());
}
令我惊讶的是,GCC和Clang没有做到这一点。例如,克朗说
Compilation finished with errors:
source.cpp:8:10: error: no matching constructor for initialization of 'A'
f(A());
^~~
source.cpp:1:21: note: candidate constructor not viable: expects an l-value for 1st argument
struct A { A(); A(A&); };
^
source.cpp:1:16: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
struct A { A(); A(A&); };
^
source.cpp:4:13: note: passing argument to parameter here
void f(A);
为什么他们选择第一个f
,而第二个f
工作正常?如果删除第一个f
,则调用成功。更奇怪的是,如果我使用大括号初始化,它也可以正常工作
他们都叫第二个
f
这是一种语言怪癖。第一个f
匹配得更好,因为A
不需要转换来匹配参数类型(A
),但当编译器尝试调用时,找不到合适的副本构造函数这一事实会导致调用失败。在执行重载解析步骤时,该语言不允许考虑实际调用的可行性
最接近匹配的标准引用ISO/IEC 14882:2011 13.3.3.1.2用户定义的转换序列[超过.ics.User]:
将类类型的表达式转换为相同的类类型时,会给出精确的匹配秩,并且
将类类型的表达式转换为该类型的基类时,尽管
对于这些情况,将调用复制/移动构造函数(即,用户定义的转换函数)
对于列表初始化情况,您可能需要查看:
13.3.3.1.2用户定义的转换序列[超过ics用户]
当列表初始化非聚合类类型T的对象时(8.5.4),重载解析选择构造函数
分两个阶段:
-最初,候选函数是T类和
参数列表由初始值设定项列表作为单个参数组成
-如果没有找到可行的初始值设定项列表构造函数,将再次执行重载解析,其中
候选函数是类T的所有构造函数,参数列表由元素组成
初始值设定项列表的
因为重载解决方案必须在每种情况下查看
f(A)
和f(B)
的可行构造函数,它必须拒绝尝试将A()
绑定到A(A&)
的序列,但是B(const A&)
仍然可行。谢谢!对于{…}
案例,我找不到这样的规则。这是否解释了{…}
案例工作的原因?@johanneschaub-litb:我不确定,tbh,您正在使用带括号的init列表调用函数,因此规则肯定不同。@johanneschaub-litb请参阅[over.ics.list]。我认为这与[over.ics.ref]/3有关(我之前误读了您的代码):当形成可行函数的子集时,ctorA(A&)
被认为是不可行的,因为它将临时引用绑定到非常量左值引用。
int main() {
f({A()});
}