c++ - 参数类型的函数具有选择的非常量引用的复制构造函数?

标签 c++ rvalue overload-resolution const-reference

前段时间,当我想编写 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/

相关文章:

c++ - 编写 c++ 函数 format_string 进行格式化,如 std::string 的 sprintf

c++ - 文字值的范围是什么,编译器如何为其分配内存?

c++ - 我什么时候应该选择复制省略而不是通过 const 引用传递参数?

c++ - C++ 中的重载 lambda 以及 clang 和 gcc 之间的区别

函数中的 C++ const 参数

c++ - 为什么 gcc8.3 似乎试图编译未使用的模板函数?

c++ - Ostream& operator<< 重载代码不起作用

c++ - 声明 RValue 方法(例如 void opera() &&;) virtual C++1x 有意义

c++ - 重载调用不明确 : one-pair inline map as constructor argument

C# 4.0 编译时错误,当错误的重载包含未引用的 .NET 组件中定义的参数类型时无法解析重载