【问题标题】:C++ forwarding reference and r-value referenceC++ 转发引用和右值引用
【发布时间】:2018-02-10 06:42:42
【问题描述】:

我了解转发引用是“对 cv 不合格模板参数的右值引用”,例如在

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

这意味着上面的函数可以同时接受左值和右值引用。

有些东西我不明白,例如

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&&和U&&都是转发引用吗?

我写了一些代码来测试(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) 如果它们正在转发引用,它们都应该编译,但两者都没有。

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

编辑 - - - - - - - 多谢你们 - - - - - - Richard 和 Artemy 是正确的。

【问题讨论】:

  • 无关,我不知道在这个时代,VS2015 工具链接受void main() 是可悲还是超现实。真的吗?
  • 在你最后一个关闭的情况下 U 没有被推导出 - 所以你的情况不会编译。为了使其可演绎,将其称为 test.test2(a);并在测试 2 中将 forward 更改为 forward

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


【解决方案1】:

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

template <class T>
class A
{
    template <class U>
    void foo(T&& t, U&& u);
};

在这个例子中,T 没有被推导(你在实例化模板时明确定义它)。

U 是推导出来的,因为它是从参数 u 推导出来的。

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

std::move(t);
std::forward<U>(u);

【讨论】:

  • BTW std::forward&lt;T&gt;(t); 将等同于 std::move(t); 在这种情况下(但不太明确)。
【解决方案2】:

T&& 和 U&& 都是转发引用吗?

不,只有U&amp;&amp; 是一个转发引用,因为U 是唯一被推导出的模板参数。在实例化 A 时,T 已经被“选择”了。

【讨论】:

    【解决方案3】:

    除了 Richard 和 Artemy 指出的,当您指定 test.test2&lt;A&gt;( a ) 时,类型 X 已经明确定义为 A。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      相关资源
      最近更新 更多