C ++转发参考和r值参考

时间:2017-09-01 08:33:55

标签: c++ rvalue-reference forwarding-reference

据我所知,转发引用是“对cv-nonqualified模板参数的右值引用”,例如

template <class T> void foo(T&& );

这意味着上述函数可以同时采用l值和r值引用。

有一些我不理解的东西,例如。

template <class T>
class A
{
    template <class U>
    void foo(T&& t, U&& u)
    {
        T t2( std::forward(t) ); // or should it be std::move(t)? is T&& forwarding or r-value reference
        U u2( std::forward(u) ); // or should it be std::move(u)? I believe U&& is forwarding reference
    }
};

在上面的代码中,都是T&amp;&amp;和U&amp;&amp;转发参考?

我写了一些代码来测试(VS2015编译器):

class A
{
public:
    A(){};
    A(const A& rhs)
    {
        std::cout << "calling 'const A&' l-value" << std::endl;
    }

    A(A&& rhs)
    {
        std::cout << "calling ' A&&' r-value" << std::endl;
    }

};

template <class T>
class Test
{
public:
    void test1(T&& t)
    {
        T t2(std::forward<T>(t));
    }

    template <typename X>
    void test2(X&& x)
    {
        T t2( std::forward<T>( x ) );
    }

};

void main()
{
    A a;
    Test<A> test;
    test.test1(A());
    test.test1(std::move(a));
    //test.test1(a); // this doesn't compile. error: cannot convert argument 1 from 'A' to 'A &&', You cannot bind an lvalue to an rvalue reference

    test.test2<A>(A());
    test.test2<A>( std::move( a ) );

    //test.test2<A>( a ); // this doesn't compile. error: cannot convert argument 1 from 'A' to 'A &&', You cannot bind an lvalue to an rvalue reference
}

我期待test.test1(a);并且test.test2(a)如果它们是转发引用则应该编译,但两者都没有。

有人可以向我解释一下吗?谢谢!

修改 - - - - - - - 多谢你们 - - - - - - 理查德和阿泰米是对的。

3 个答案:

答案 0 :(得分:3)

这是一个很好的问题,几乎每个人都在开始。

T

在此示例中,未推导出U(您在实例化模板时明确定义它)。

u的推断是因为它是从参数std::move(t); std::forward<U>(u); 中推导出来的。

因此,几乎在所有情况下都是:

<?php $paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
query_posts(
  array(
    'paged' => $paged,
    'post_type' => 'galleries',
    'posts_per_page' => 7
  ) ); ?>

答案 1 :(得分:3)

  

都是T&amp;&amp;和U&amp;&amp;转发参考?

不,只有U&&转发引用,因为U是唯一被推断的模板参数。在实例化T时,A已被“选中”。

答案 2 :(得分:0)

除了 Richard 和 Artemy 指出的之外,当您指定 test.test2<A>( a ) 时,类型 X 已经明确定义为 A。

当您将其更改为 test.test2( a ) 时,应该推导出类型 X 并且应该可以编译。