为什么不总是使用std :: forward?

时间:2016-03-25 22:05:02

标签: c++ c++11

std::movestd::forward之间的区别是众所周知的,我们使用后者保留转发对象的值类别,并使用前者转换为右值引用以启用移动语义。

有效的现代C ++ 中,存在一个指出

的指南
  

在rvalue引用上使用std::move,在通用引用上使用std::forward

但在以下情况中(以及我们不想更改值类别的情况),

template <class T>
void f(vector<T>&& a)
{
    some_func(std::move(a)); 
}

其中a不是转发引用,而是简单的右值引用,与以下内容完全相同不是吗?

template <class T>
void f(vector<T>&& a)
{
    some_func(std::forward<decltype(a)>(a)); 
}

因为这可以很容易地封装在像这样的宏中,

#define FWD(arg) std::forward<decltype(arg)>(arg)

总是像这样使用这个宏定义是否方便?

void f(vector<T>&& a)
{
    some_func(FWD(a)); 
}

Aren的两种写法完全相同吗?

1 个答案:

答案 0 :(得分:7)

的Eh。值得商榷。在您的特定示例中,它是等效的。但我不会养成习惯。一个原因是因为您希望在转发和移动之间进行语义区分。另一个原因是因为要拥有一致的API,除了MOV之外,您还必须拥有FWD,而且这看起来很糟糕,并且没有做任何事情。但更重要的是,您的代码可能会意外失败。

请考虑以下代码:

#include <iostream>

using namespace std;

#define FWD(arg) std::forward<decltype(arg)>(arg)

struct S {
    S() { cout << "S()\n"; }
    S(const S&) { cout << "S(const S&)\n"; }
    S(S&&) { cout << "S(S&&)\n"; }
};

void some_func(S) {}

void f(S&& s)
{
    some_func(FWD(s)); 
}

int main()
{
    f(S{});
}

打印出来

  

S()
  S(S&安培;&安培;)

但是,如果我只是将FWD行更改为另一对(看似可选的)括号,如下所示:

void f(S&& s)
{
    some_func(FWD((s))); 
}

现在我们得到

  

S()
  S(const S&amp;)

这是因为现在我们在表达式上使用decltype,该表达式计算为左值引用。