rvalue模板参数隐式用作左值,std :: forwarding工作

时间:2012-04-30 20:12:55

标签: c++ templates c++11 rvalue-reference perfect-forwarding

关于std::forward用法的{p> This example令我感到困惑。这是我编辑的版本:

#include <iostream>
#include <memory>
#include <utility>
using namespace std;

struct A{
    A(int&& n) { cout << "rvalue overload, n=" << n << "\n"; }
    A(int& n)  { cout << "lvalue overload, n=" << n << "\n"; }
};

template<typename> void template_type_dumper();

template<class T, class U>
unique_ptr<T> make_unique(U&& u){
    //Have a "fingerprint" of what function is being called
    static int dummyvar;
    cout<<"address of make_unique::dummyvar: "<<&dummyvar<<endl;
    //g++ dumps two warnings here, which reveal what exact type is passed as template parameter
    template_type_dumper<decltype(u)>;
    template_type_dumper<U>;

    return unique_ptr<T>(new T(forward<U>(u)));
}

int main()
{
    unique_ptr<A> p1 = make_unique<A>(2); // rvalue
    int i = 1;
    unique_ptr<A> p2 = make_unique<A>(i); // lvalue
}

输出

address of make_unique::dummyvar: 0x6021a4
rvalue overload, n=2
address of make_unique::dummyvar: 0x6021a8
lvalue overload, n=1

并且有关template_type_dumper引用的警告显示,在第一个实例中decltype(u) = int&&U = int,第二个decltype(u) = int&U = int&

很明显,有两种不同的实例可以预期,但她是我的问题:

  1. std::forward如何在这里工作?在第一个实例化中,它的模板参数是显式的U = int,它怎么知道它必须返回一个rvalue-reference?如果我指定U&&而会发生什么?
  2. 声明
  3. make_unique采用右值引用。为什么u可以成为左值参考?我有什么特别的规则吗?

1 个答案:

答案 0 :(得分:4)

  声明

make_unique采用右值引用。你怎么能成为左值参考?我缺少什么特殊规则?

make_unique被声明为参考。这个参考是什么样的推论。如果传递了foo类型的左值,则U被推断为foo&U&&变为foo&,因为参考折叠规则(基本上是“合并”)带有另一个引用的左值引用总是产生左值引用;组合两个右值引用会产生右值引用。如果传递了foo类型的左值,则U推断为fooU&&foo&&

这是完美转发的重要因素之一:使用U&&,您可以同时使用左值和左值,并推导U以匹配适当的值类别。然后使用std::forward,您可以转发保留相同值类别的值:在第一种情况下,您获得转发左值的std::forward<foo&>,在第二种情况下,您获得std::forward<foo>转发一个右值。

  

在第一个实例化中,它的模板参数显式为U = int,它怎么知道它必须返回一个rvalue-reference?

因为std::forward<T>的返回类型始终为T&&。如果您通过int,则会返回int&&。如果您通过int&,则会因参考折叠规则而再次返回int&

  

如果我指定U&amp;&amp;代替?

您将拥有std::forward<int&&>,并且参考折叠规则会使int&& &&成为左值参考:int&&