[英]Preventing non-const lvalues from resolving to rvalue reference instead of const lvalue reference
I'm having trouble overloading a function to take a value either by const reference or, if it is an rvalue, an rvalue reference. 我无法通过const引用重载函数来获取值,或者如果它是rvalue则是rvalue引用。 The problem is that my non-const lvalues are binding to the rvalue version of the function. 问题是我的非const左值绑定到函数的右值版本。 I'm doing this in VC2010. 我在VC2010中这样做。
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void foo(const T& t)
{cout << "void foo(const T&)" << endl;}
template <class T>
void foo(T&& t)
{cout << "void foo(T&&)" << endl;}
int main()
{
vector<int> x;
foo(x); // void foo(T&&) ?????
foo(vector<int>()); // void foo(T&&)
}
The priority seems to be to deduce foo(x) as 优先级似乎是推导foo(x)为
foo< vector<int> & >(vector<int>& && t)
instead of 代替
foo< vector<int> >(const vector<int>& t)
I tried replacing the rvalue-reference version with 我尝试用r替换rvalue-reference版本
void foo(typename remove_reference<T>::type&& t)
but this only had the effect of causing everything to resolve to the const-lvalue reference version. 但这只会导致所有内容都解析为const-lvalue引用版本。
How do I prevent this behaviour? 我该如何防止这种行为? And why is this the default anyway - it seems so dangerous given that rvalue-references are allowed to be modified, this leaves me with an unexpectedly modified local variable. 为什么这仍然是默认值 - 考虑到允许修改rvalue-references似乎很危险,这给我留下了意外修改的局部变量。
EDIT: Just added non-template versions of the functions, and they work as expected. 编辑:刚添加了非模板版本的函数,它们按预期工作。 Making the function a template changes the overload resolution rules? 将函数设为模板会更改重载决策规则吗? That is .. really frustrating! 那真是令人沮丧!
void bar(const vector<int>& t)
{cout << "void bar(const vector<int>&)" << endl;}
void bar(vector<int>&& t)
{cout << "void bar(vector<int>&&)" << endl;}
bar(x); // void bar(const vector<int>&)
bar(vector<int>()); // void bar(vector<int>&&)
When you have a templated function like this you almost never want to overload. 当你有一个模板函数这样你几乎从来没有要过载。 The T&&
parameter is a catch anything parameter. T&&
参数是一个catch任何参数。 And you can use it to get any behavior you want out of one overload. 并且您可以使用它从一个重载中获取您想要的任何行为。
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void display()
{
typedef typename remove_reference<T>::type Tr;
typedef typename remove_cv<Tr>::type Trcv;
if (is_const<Tr>::value)
cout << "const ";
if (is_volatile<Tr>::value)
cout << "volatile ";
std::cout << typeid(Trcv).name();
if (is_lvalue_reference<T>::value)
std::cout << '&';
else if (is_rvalue_reference<T>::value)
std::cout << "&&";
std::cout << '\n';
}
template <class T>
void foo(T&& t)
{
display<T>();
}
int main()
{
vector<int> x;
vector<int> const cx;
foo(x); // vector<int>&
foo(vector<int>()); // vector<int>
foo(cx); // const vector<int>&
}
In order for T&&
to bind to an lvalue reference, T
must itself be an lvalue reference type. 为了使T&&
绑定到左值引用, T
必须本身是左值引用类型。 You can prohibit the template from being instantiated with a reference type T
: 您可以禁止使用引用类型T
实例化模板:
template <typename T>
typename std::enable_if<!std::is_reference<T>::value>::type foo(T&& t)
{
cout << "void foo(T&&)" << endl;
}
enable_if
is found in <utility>
; enable_if
在<utility>
找到; is_reference
is found in <type_traits>
. is_reference
可在<type_traits>
找到。
The reason that the overload taking T&&
is preferred over the overload taking a T const&
is that T&&
is an exact match (with T = vector<int>&
) but T const&
requires a qualification conversion (const-qualification must be added). 过载T&&
的优先选择优先于过载采用T const&
并且T&&
是完全匹配( T = vector<int>&
)但是T const&
需要资格转换(必须添加const限定)。
This only happens with templates. 这只发生在模板上。 If you have a nontemplate function that takes a std::vector<int>&&
, you will only be able to call that function with an rvalue argument. 如果你有一个带有std::vector<int>&&
的nontemplate函数,你只能使用rvalue参数调用该函数。 When you have a template that takes a T&&
, you should not think of it as "an rvalue reference parameter;" 当你有一个采用T&&
的模板时,你不应该把它想象成“一个右值参考参数;” it is a "universal reference parameter" (Scott Meyers used similar language, I believe). 它是一个“通用参考参数”(Scott Meyers使用类似语言,我相信)。 It can accept anything. 它可以接受任何东西。
Allowing a T&&
parameter of a function template to bind to any category of argument is what enables perfect forwarding. 允许函数模板的T&&
参数绑定到任何类别的参数是实现完美转发的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.