当我知道传入的类型时,完美转发的最佳方法是什么

时间:2013-06-20 09:09:13

标签: c++ c++11

如果我理解正确,完美转发使用通用引用推断传递的参数是l值或r值。很不错。

这意味着,要实现此功能,我必须制作模板功能。 一个可能的例子是

template <class T>
void func(T&& str){
    auto s = std::forward<T>(str);
    cout << s << endl;
}

但是,如果我知道T的{​​{1}}应仅func,该怎么办?我认为一种可能的选择是使用std::stringstd::enable_if来限制类型std::is_same。但它变得越来越冗长。

这种情况的最佳做法是什么?

编辑:

正如Kerrek SB所建议的那样,我正在尝试制作一个可能的场景。

我正在创建一个以T为成员的班级。 然后,我想创建一个也需要std::vector<double>的构造函数。 如果参数是l值,我想将其复制到成员,但如果不是,我想移动它。

这是某种可能的例子吗?

2 个答案:

答案 0 :(得分:3)

如果您不想要模板,您有两种选择:

  1. 按值传递并移动;
  2. 有一个副本用于副本,一个用于移动;
  3. 第一个选项将允许编译器根据需要决定移动或复制到您的参数。然后你的代码不再关心它是来自左值还是右值(如果它来自左值,它已经是副本)并将其移动到成员中。除了优化之外,这可能会有一次移动的开销,但如果移动很便宜(如std::vector的话),则可能忽略不计。

    foo(std::vector<double> v) : v(std::move(v)) {}
    

    使用第二个选项,您的代码会做出决定,而不是编译器。这避免了一次移动的上述可能开销,但它存在不可扩展的问题:如果有四个这样的参数要复制或移动,则需要十六个不同的重载(这个确切的问题是完美转发尝试解决的问题) )。

    foo(std::vector<double> const& v) : v(v) {}
    foo(std::vector<double>&& v) : v(std::move(v)) {}
    

    模板选项可以正确缩放,但可能需要一些约束来防止在不需要的情况下使用它(在无约束模板构造函数的情况下,它可以是mistakenly used for copies)。

    当然,如果您使用的是移动退化为副本的类型(如std::array),您可以使用此集合的第一个重载。

答案 1 :(得分:2)

按值传递。

该情况下,用户决定是否希望他的矢量结束被销毁。当参数明显是一个右值时(例如,当将向量构造为函数调用中的临时值时),它也将按预期工作。完美转发是错误的工具。