如果我理解正确的话,完美转发使用通用引用来推断传递的参数是左值还是右值。这很好。
也就是说,要实现这个功能,我必须制作模板函数。 一个可能的例子是
template <class T>
void func(T&& str){
auto s = std::forward<T>(str);
cout << s << endl;
}
但是,如果我知道 T
怎么办?的 func
应该是 std::string
仅有的?我认为一种可能的选择是使用 std::enable_if
和 std::is_same
限制类型 T
.但它变得越来越冗长。
这种情况的最佳做法是什么?
编辑:
根据 Kerrek SB 的建议,我正在尝试制作一个可能的场景。
我正在制作一个包含 std::vector<double>
的类(class)作为成员(member)。
然后,我想制作一个也采用 std::vector<double>
的构造函数.
如果参数是左值,我想将它复制到一个成员,但如果不是,我想移动它。
这是某种可能的例子吗?
最佳答案
如果您不想要模板,您有两个选择:
- 按值传递并移动;
- 有一个拷贝重载和一个移动重载;
第一个选项将让编译器根据需要决定是移动还是复制到您的参数中。然后你的代码不再关心它是来自左值还是右值(如果它来自左值它已经是一个拷贝)并将其移动到成员中。撇开优化不谈,这可能会产生一次移动的开销,但如果移动成本较低(如 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
),您可以只使用该集合的第一个重载。
关于c++ - 当我知道传入的类型时,完美转发的最佳方式是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17209650/