前段时间,当我想编写 is_callable<F, Args...>
时,我对某些代码的以下行为感到困惑特征。重载解析不会调用接受非常量引用参数的函数,对吧?为什么它在下面不拒绝,因为构造函数想要一个 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)。无法从您提供的右值复制测试,但重载解析已成功...从不检查到 int 的转换。
选择g(Eater)
是因为类型不完全匹配,不使用恒等转换,并且编译器必须找到有效的转换例程。 g(Slurper)
不会,因为您无法从提供的参数中得出一个结果。
“为什么这个没有失败:struct A { operator int(); }; void f(A&); void f(int); void g() { f(A()); }
“
因为 f(A&) 对于所提供的参数来说不是可行的重载。在这种情况下,参数是一个引用,并且临时值不绑定(bind)到非常量这一事实可以影响解析。在这种情况下,它确实如此,并且该函数的该版本成为非候选版本,只留下一个可以运行的版本。
关于c++ - 参数类型的函数具有选择的非常量引用的复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4704567/