超载的调用是模棱两可的
Call of overload is ambigious
我正在学习新的C++语义,但这个程序出错了:
#include <iostream>
#include <string>
#include <utility>
std::string foo(std::string str)
{
return str + " call from normal";
}
std::string foo(const std::string& str)
{
return str + " call from normal";
}
std::string foo(std::string&& str)
{
return str + " call from ref ref";
}
int main()
{
std::string str = "Hello World!";
std::string res = foo(str);
std::string&& res_ref = foo(std::move(str));
std::cout << "Res ref = " << res_ref << std::endl;
std::cout << "Str = " << str << std::endl;
return 0;
}
错误是:
:23:30: error: call of overloaded ‘foo(std::__cxx11::string&)’ is ambiguous std::string res = foo(str);
为什么通话模棱两可?
当你有;
std::string res = foo(str);
有两个可行的候选者:
foo(std::string ); // #1
foo(std::string const& ); // #2
在给定多个候选者时,确定选择哪个函数的步骤很多很多。但在这种情况下,这两种选择都是完全无法区分的 - 在string
和string const&
之间的重载分辨率中根本没有参数的偏好。同样,对于 rvalue 参数,string
和string&&
之间没有首选项,因此您的第二次调用也被认为是模棱两可的。
通常,偏爱一个函数而不是另一个函数的规则与哪个函数更具体有关。例如,给定一个函数取string&
和一个取string const&
的函数,前者只能用对string
的非常量左值引用来调用,但后者可以用一大堆东西来调用,所以当两者都可行时,前者是首选的(特别是由于[over.ics.rank]/3.2.6)。但在这种情况下,任何你可以打电话给#1
的东西,你都可以打电话给#2
。任何你可以打电话给#2
的东西,你都可以打电话给#1
。因此,没有任何理由偏爱其中之一。
您应该简单地删除该重载,留下两个:
foo(std::string const& ); // #2
foo(std::string&& ); // #3
对于左值std::string
s,只有 #2 可行。对于std::string
s 的右值,两者都是可行的,但 #3 是首选(根据一般准则,它更具体 - 特别是由于 [over.ics.rank]/3.2.3)。
为了清楚起见,忘记右值引用(string&&)引用,假装你是编译器。
定义了两个函数:
- foo(std::string str)
- foo(const std::string& str)
给定 str 是一个 std::字符串,要求您调用:
foo(str);
你要调用哪个函数,1 还是 2?
- 您可以将 str 传递给 foo 1。
- 您可以将对 str 的常量引用(如指针)传递给 foo 2。
在这种情况下,您可以执行任一操作,因此编译器无法决定。
编译器如何决定?有一些规则涉及创建候选函数列表、可以对参数执行哪种类型提升或转换,以及可以使用哪些构造函数来创建所需的参数。这是一门课程的简单概述。
歧义在于这两个函数之间:
std::string foo(std::string str); // 1
std::string foo(const std::string& str); // 2
读取函数名称的方式是从右到左。这些函数的英文等效项是:
foo
是一个接受std::string
参数并返回std::string
的函数。foo
是一个函数,它接受对constant std::string
参数的reference
并返回std::string
。
分别。
编译器在这两个函数签名之间唯一已知的区别是,是将str
的副本作为参数还是对str
的不可变引用。从编译器的角度来看,这两个函数没有足够的差异,无法在运行时对它们进行偏好。
通常,如果它不是基元类型(即 int、char、short 等),请使用引用而不是类型本身。对于所有意图和目的,std::string
类似于std::vector<char>
因此,无论字符串的长度如何,通过引用传递它始终会花费您sizeof(pointer)
数据事务。
- 调用重载的"<大括号括起来的初始值设定项列表>"对于对来说就足够了是模棱两可的
- 为什么对模板的调用不模棱两可?
- 模棱两可的调用 - 模板化函数
- C++ lambda 模棱两可的调用
- C++11 中对超载'ref(Select::Expressions::Code&)'的调用模棱两可
- 是可调用和模棱两可的调用:g++ 或 clang 中的错误
- 超载的调用是模棱两可的
- C 从同一基本模板类覆盖功能,具有多个继承模棱两可的函数调用
- MSVC发现这种方法调用模棱两可,而Clang / GCC则不然吗?
- 为模棱两可的超载功能调用创建默认值
- 重载函数的调用 - 以继承的类作为参数 - 是模棱两可的
- 为什么对函数的调用"sample_mean"模棱两可的?
- 对 glm::slerp 的模棱两可的调用
- 超载的调用是模棱两可的
- 对重载函数的模棱两可的调用,即使一个更专业
- 为什么 main() 中的调用 'A a(c);' 不模棱两可?
- Gtkmm,重载的'Scale()'的调用是模棱两可的
- 调用重载<大括号括起来的初始值设定项列表>是模棱两可的,如何处理?
- 调用超载to_string模棱两可
- 对函数的调用在C++中是模棱两可的.候选函数是原型和函数本身