考虑这个简单的代码片段:
static void Foo(std::string&& arg) {
printf("(universal reference) = %s\n", arg.c_str());
}
static void Foo(const std::string&& arg) {
printf("(const universal reference) = %s\n", arg.c_str());
}
static void Foo(std::string& arg) {
printf("(reference) = %s\n", arg.c_str());
}
static void Foo(const std::string& arg) {
printf("(const reference) = %s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value);
Foo(const_value);
Foo(std::string("temporary"));
Foo("litteral");
}
Clang下的结果输出是:
(reference) = value
(const reference) = const_value
(universal reference) = temporary
(universal reference) = literal
为什么value
不使用函数的通用引用版本?我认为普遍引用的一个主要好处是它们可以同时接受左值和右值?
PS:也不可能强迫它:
static void Foo(std::string&& arg) {
printf("(universal reference) = %s\n", arg.c_str());
}
//static void Foo(const std::string&& arg) {
// printf("(const universal reference) = %s\n", arg.c_str());
//}
//
//static void Foo(std::string& arg) {
// printf("(reference) = %s\n", arg.c_str());
//}
//
//static void Foo(const std::string& arg) {
// printf("(const reference) = %s\n", arg.c_str());
//}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value); <--- FAILS COMPILING: No matching function for call to 'Foo'
// Foo(const_value);
Foo(std::string("temporary"));
Foo("literal");
}
更新:看来“通用引用”仅适用于模板,而不是常规功能,这就解释了为什么上述内容无法正常工作。
但是这是一个使用模板化函数的版本:
template<typename T>
static void Foo(T&& arg) {
printf("%s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo<std::string>(value); <--- FAILS COMPILING: No matching function for call to 'Foo'
Foo<std::string>(const_value); <--- FAILS COMPILING: No matching function for call to 'Foo'
Foo<std::string>(std::string("temporary"));
Foo<std::string>("literal");
}
为什么value
案例仍未通过通用引用(我明白为什么const_value
不是这样)?
更新:供参考,这是适用于左值和右值的最终版本:
template<typename T>
static void Foo(T&& arg) {
printf("%s\n", arg.c_str());
}
int main(int argc, const char * argv[]) {
std::string value{"value"};
const std::string const_value{"const_value"};
Foo(value);
Foo(const_value);
Foo(std::string("temporary"));
//Foo("literal"); <--- Cannot work anyway since template is instantiated with arg as a const char*
}
答案 0 :(得分:2)
那些不是&#34;普遍参考&#34;。这些只是左值参考。
A&#34; universal reference&#34; (仅供参考:此术语不受欢迎)明确指出在使用模板参数推导时,直接应用于完全模板推导类型的rvalue引用(与vector<T> &&v
相反,仅部分推导)。您的所有函数都不是模板函数,因此它们的行为类似于常规的右值引用。
foo(value)
调用左值引用版本,因为作为参数传递的变量绑定到左值引用参数类型。
然而,这是一个使用模板化函数的版本:
这些函数都不使用模板参数推导。您直接明确指定模板参数,不允许通过您调用它的参数推断出它。
或更重要的是:
Foo<std::string>(value);
Foo(value);
Foo<std::string>(std::string("temporary"));
Foo(std::string("temporary"));
在第一种情况下,T
是std::string
,因为您指定它是Foo<std::string>
。因此,std::string&&
需要value
。 T
无法绑定到右值引用,因此它是编译错误。
在第二种情况下,value
是基于参数表达式通过模板参数推导推导出的。 T
是左值,因此std::string&
推断为Foo
。因此,在这种情况下,std::string& &&
需要std::string&
,其范围可降至T
。
在第三种情况下,std::string
为Foo<std::string>
。因此,std::string&&
再次T
。临时可以很好地绑定到右值参考,所以它就这样做了。
在第四种情况下,std::string
是基于参数表达式通过模板参数推导推导出的。表达式是T
临时prvalue,因此std::string
推导为Foo
(请注意缺少引用)。因此,std::string&&
在这种情况下需要{{1}}。