0

如果我理解正确,完美转发使用通用引用来推断传递的参数是左值还是右值。很好。

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

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

T但是,如果我知道func应该std::string只是呢?我认为一种可能的选择是使用std::enable_ifandstd::is_same来限制 type T。但它变得越来越冗长。

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

编辑:

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

我正在做一个有std::vector<double>成员的课程。然后,我想做一个构造函数,它也需要std::vector<double>. 如果参数是左值,我想将它复制到一个成员,但如果不是,我想移动它。

这是某种可能的例子吗?

4

2 回答 2

3

按值传递。

在这种情况下,用户决定是否要销毁他的向量末端。当参数明显是右值时(例如,在函数调用中将向量构造为临时变量时),它也将按预期工作。完美转发在这里是错误的工具。

于 2013-06-20T09:24:15.053 回答
3

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

  1. 按值传递并移动;
  2. 一个用于复制,一个用于移动;

第一个选项将让编译器根据需要决定是移动还是复制到您的参数中。然后你的代码不再关心它是来自左值还是右值(如果它来自左值,它已经是一个副本)并将其移动到成员中。抛开优化不谈,这可能会产生一次移动的开销,但如果移动很便宜(例如 的情况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)) {}

模板选项将正确缩放,但可能需要一些约束以防止其在不希望的情况下使用(在不受约束的模板构造函数的情况下,它可能被错误地用于副本)。

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

于 2013-06-20T09:28:29.743 回答