如果我理解正确,完美转发使用通用引用推断传递的参数是l值或r值。很不错。
这意味着,要实现此功能,我必须制作模板功能。 一个可能的例子是
template <class T>
void func(T&& str){
auto s = std::forward<T>(str);
cout << s << endl;
}
但是,如果我知道T
的{{1}}应仅func
,该怎么办?我认为一种可能的选择是使用std::string
和std::enable_if
来限制类型std::is_same
。但它变得越来越冗长。
这种情况的最佳做法是什么?
编辑:
正如Kerrek SB所建议的那样,我正在尝试制作一个可能的场景。
我正在创建一个以T
为成员的班级。
然后,我想创建一个也需要std::vector<double>
的构造函数。
如果参数是l值,我想将其复制到成员,但如果不是,我想移动它。
这是某种可能的例子吗?
答案 0 :(得分: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)
按值传递。
该情况下,用户决定是否希望他的矢量结束被销毁。当参数明显是一个右值时(例如,当将向量构造为函数调用中的临时值时),它也将按预期工作。完美转发是错误的工具。