我正在学习新的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);
为什么电话不明确?
答案 0 :(得分:6)
当你有;
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
,只有#2是可行的。对于右值std::string
,两者都是可行的,但#3是首选(根据一般指导原则,它更具体 - 特别是由于[over.ics.rank]/3.2.3)。
答案 1 :(得分:-2)
为了清楚起见,忘掉右值参考(字符串&amp;&amp;),并假装你是编译器。
定义了两个功能:
鉴于str是std :: string,您需要调用:
foo(str);
你要拨打哪个功能,1或2?
在这种情况下你可以做任何一个,所以编译器无法决定。
编译器如何决定?有关于创建候选函数列表的规则,可以对参数执行何种类型的促销或转换,以及可以使用哪些构造函数来创建所需的参数。 Here is a simple overview来自课程。
答案 2 :(得分:-2)
模糊性介于这两个功能之间:
std::string foo(std::string str); // 1
std::string foo(const std::string& str); // 2
您阅读函数名称的方式是从右到左。这些函数的英语等价物是:
foo
是一个接受std::string
参数并返回std::string
的函数。foo
是一个将reference
转换为constant std::string
参数并返回std::string
的函数。分别
这两个函数签名之间编译器已知的唯一区别是,是将str
的副本作为其参数还是对str
的不可变引用。从编译器的角度来看,这两个函数没有足够的差异,在运行时期间对它们有偏好。
通常,如果它不是基本类型(即int,char,short等),请使用引用而不是类型本身。对于所有意图和目的,std::string
与std::vector<char>
类似,因此无论字符串的长度是多少,通过引用传递它总是花费sizeof(pointer)
数据事务。