我无法通过const引用重载函数来获取值,或者如果它是rvalue则是rvalue引用。问题是我的非const左值绑定到函数的右值版本。我在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&&)
}
优先级似乎是将foo(x)推断为
foo< vector<int> & >(vector<int>& && t)
而不是
foo< vector<int> >(const vector<int>& t)
我尝试用
替换rvalue-reference版本void foo(typename remove_reference<T>::type&& t)
但这只会导致所有内容都解析为const-lvalue引用版本。
如何防止此行为?为什么这仍然是默认值 - 考虑到允许修改rvalue-references似乎很危险,这给我留下了意外修改的局部变量。
编辑:刚添加了非模板版本的函数,它们按预期工作。将函数设为模板会更改重载决策规则吗?那真是令人沮丧!
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>&&)
答案 0 :(得分:24)
当你有这样的模板化功能时,你几乎从不想要超载。 T&&
参数是捕获任何参数。您可以使用它来获取一个重载所需的任何行为。
#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>&
}
答案 1 :(得分:12)
为了使T&&
绑定到左值引用,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
中找到 <utility>
; is_reference
中找到了<type_traits>
。
过载T&&
优先于过载T const&
的原因是T&&
与T = vector<int>&
完全匹配,但是T const&
需要资格转换(必须添加const-qualification)。
这仅适用于模板。如果你有一个带有std::vector<int>&&
的非模板函数,你将只能用一个rvalue参数调用该函数。如果您的模板采用T&&
,则不应将其视为“右值参考参数”;它是一个“通用参考参数”(Scott Meyers使用类似语言,我相信)。它可以接受任何东西。
允许函数模板的T&&
参数绑定到任何类别的参数是实现完美转发的原因。