前段时间,当我想编写is_callable< F,Args ...>时,我对某些代码的以下行为感到困惑.特征.重载解析不会调用非const ref接受参数的函数,对吗?为什么在下面它不拒绝,因为构造函数想要一个Test& ;?我希望它取f(int)!
struct Test {
Test() { }
// I want Test not be copyable from rvalues!
Test(Test&) { }
// But it's convertible to int
operator int() { return 0; }
};
void f(int) { }
void f(Test) { }
struct WorksFine { };
struct Slurper { Slurper(WorksFine&) { } };
struct Eater { Eater(WorksFine) { } };
void g(Slurper) { }
void g(Eater) { } // chooses this, as expected
int main() {
// Error, why?
f(Test());
// But this works, why?
g(WorksFine());
}
错误消息是
m.cpp: In function 'int main()':
m.cpp:33:11: error: no matching function for call to 'Test::Test(Test)'
m.cpp:5:3: note: candidates are: Test::Test(Test&)
m.cpp:2:3: note: Test::Test()
m.cpp:33:11: error: initializing argument 1 of 'void f(Test)'
您能解释一下为什么一个有效但另一个无效的原因吗?
解决方法:
重载分辨率选择与提供的参数最匹配的函数.您提供了一个测试.无需转换-使用身份转换.因此,函数解析选择f(Test).无法从您提供的rvalue复制测试,但是重载解析已经成功…从不检查是否已转换为int.
选择g(Eater)的原因是类型不完全匹配,不使用身份转换,并且编译器必须找到一个有效的转换例程. g(Slurper)不会,因为您无法从提供的参数中选择一个.
“为什么这不会失败:struct A {运算符int();}; void f(A&); void f(int); void g(){f(A());}”
因为f(A&)对于提供的参数而言不是可行的重载.在这种情况下,该参数是一个引用,并且温度不绑定到非常量这一事实可以影响分辨率.在这种情况下,该函数将变为该函数的那个版本,而该函数的那个版本将变为非候选函数,并且仅保留该函数的那个版本并起作用.