首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >防止非常量左值解析为右值引用,而不是常量左值引用

防止非常量左值解析为右值引用,而不是常量左值引用
EN

Stack Overflow用户
提问于 2011-10-13 08:26:01
回答 2查看 2.1K关注 0票数 20

我在重载一个函数时遇到了问题,通过常量引用来获取一个值,或者如果它是一个右值,那么它就是一个右值引用。问题是我的非常量左值绑定到函数的右值版本。我在VC2010中做这件事。

代码语言:javascript
复制
#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)推导为

代码语言:javascript
复制
foo< vector<int> & >(vector<int>& && t)

而不是

代码语言:javascript
复制
foo< vector<int> >(const vector<int>& t)

我尝试将rvalue-reference版本替换为

代码语言:javascript
复制
void foo(typename remove_reference<T>::type&& t)

但这只会导致一切都解析到const-lvalue参考版本。

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

编辑:只是添加了函数的非模板版本,它们可以正常工作。使函数成为模板会改变重载解决规则吗?那是..。真的很令人沮丧!

代码语言:javascript
复制
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>&&)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-10-13 08:55:22

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

代码语言:javascript
复制
#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>&
}
票数 26
EN

Stack Overflow用户

发布于 2011-10-13 08:36:20

为了使T&&绑定到左值引用,T本身必须是左值引用类型。您可以禁止使用引用类型T实例化模板

代码语言:javascript
复制
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&需要限定转换(必须添加常量限定)。

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

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

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7748104

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档