C++中完美转发的正确使用

A proper use of perfect forwarding in C++?

本文关键字:完美 转发 C++      更新时间:2023-10-16

我想知道以下是否是C++中完美转发的正确使用(解释如下):

class A
{
  public:
  //...
  template <typename T> A( T&& b,const C& c ) : _b{ std::forward<T>( b ) },_c{ c } { }
  //...
  private:
  B _b;
  C _c;
};

类型为A的对象包含BC对象。要求A对象可以单独由一对(B bC c)构成。现在上下文规定,对于这样的构造,c必须复制_c中。因此,c被传递为const C&。另一方面,根据情况,必须将b复制到_b,或者可以将b移动到_b。上面的代码会正确地实现这一点吗?也就是说,它会根据代码中构造A类型对象的方式生成适当的构造函数吗?也就是说,这是完美转发的正确使用吗?

我认为它做了正确的事情,但我生气的原因是:我认为这有点难看,因为我只想在第一个参数中调用具有B类型的lvalues或rvalues的构造函数。上述代码原则上允许任何类型的T。定义两种方法的替代方案是吗

A( B& b,const C& c ) : _b{ b },_c{ c } { }
A( B&& b,const C& c ) : _b{ std::move( b ) },_c{ c } { }

是首选吗?

任何可以作为一个参数构造B的东西都可以在示例代码中使用。

这并不是一件坏事。

如果B有一个采用int的构造函数,则可以传递一个int作为第一个参数。它将直接从int构造结构中的B,而不是创建临时B然后将其移动到您的结构中。

如果你真的,真的想要你所描述的,你可以用三种方法来强制执行:

// copy:
A( B const& b,const C& c ) : _b{ b },_c{ c } { }
// move:
A( B&& b,const C& c ) : _b{ std::move( b ) },_c{ c } { }

template <typename T, typename=std::enable_if<
  std::is_same<
    typename std::decay<T>::type,
    B
  >::value
>::type> A( T&& b,const C& c ) : _b{ std::forward<T>( b ) },_c{ c } { }

其阻止任何类型的转换。最后,如果B移动起来很便宜,你可以做:

A( B b, const C& c ): _b(std::move(b)), _c(std::move(c)) {}

它遵循成语"如果你想要速度,就按价值传递"。

这里,从参数到B的隐式转换也被阻止,除非调用者显式转换。