20

我在重载一个函数以通过 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)

我尝试将右值引用版本替换为

void foo(typename remove_reference<T>::type&& t)

但这只会导致所有内容都解析为 const-lvalue 参考版本。

如何防止这种行为?以及为什么这是默认值 - 考虑到允许修改右值引用,这似乎很危险,这给我留下了一个意外修改的局部变量。

编辑:刚刚添加了函数的非模板版本,它们按预期工作。使函数成为模板会更改重载解析规则?那是..真令人沮丧!

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>&&)
4

2 回答 2

26

当你有一个像这样的模板化函数时,你几乎不想重载。该T&&参数是一个catch any参数。您可以使用它来从一个重载中获得您想要的任何行为。

#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>&
}
于 2011-10-13T00:55:21.563 回答
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&&优先于重载 a 的原因T const&是它T&&是完全匹配(with T = vector<int>&)但T const&需要限定转换(必须添加 const 限定)。

这只发生在模板上。如果您有一个带有 的非模板函数std::vector<int>&&,您将只能使用右值参数调用该函数。当您有一个带有 的模板时T&&,您不应将其视为“右值引用参数”;它是一个“通用参考参数”(我相信斯科特迈耶斯使用了类似的语言)。它可以接受任何东西。

允许T&&函数模板的参数绑定到任何类别的参数是实现完美转发的原因。

于 2011-10-13T00:36:19.677 回答