【问题标题】:Templates and using rvalues references as a parameter模板和使用右值引用作为参数
【发布时间】:2014-07-20 20:45:33
【问题描述】:

所以我有一个名为OptionsMapstd::map< std::string, boost::any >,我想创建一个可以采用任何类型(因此是模板)的函数并将其存储在地图中。 下一个代码会起作用吗?

template <typename T>
void Set(std::string optionName, T&& optionValue)
{
    OptionsMap[optionName] = optionValue;
}

【问题讨论】:

  • 你有理由相信它不起作用吗?
  • 如果您要进行完美转接,您错过了std::forward 的电话。
  • @KerrekSB 我还在学习右值等,所以我只是想确保
  • @chris 怎么样?请赐教
  • @user3027108, optionValue 是一个左值。见this example。将其与this one 进行比较。

标签: c++ templates rvalue-reference pass-by-rvalue-reference


【解决方案1】:

通常,当函数模板接受通用引用(即推导类型的右值引用)时,您应该使用 forward 强制转换函数参数,以便获得与提供的值类别相同的值函数调用中的参数:

template <typename T>
void Set(std::string optionName, T&& optionValue)
{
    OptionsMap[optionName] = std::forward<T>(optionValue);
    //                       ^^^^^^^^^^^^^^^
}

参数变量optionValue 本身始终是一个左值,因此如果没有强制转换,您将复制应该移动的内容。如果类型是可复制的,这将比预期的效率低;如果类型不可复制(例如unique_ptr),情况会更糟:您的函数现在接受一个参数,该参数随后将无法编译。

【讨论】:

  • 谢谢!如果我理解正确,前向函数会从左值返回右值?
  • @user3027108:不,应该是std::move。相比之下,std::forward 必须给出一个显式的模板参数,它恢复了原始参数的正确广义值类别。 (例如,见this answer。)
  • 参数optionName 不应该是左值引用,这样它就不会创建std::string 副本?
  • @ReBirTH:当然。我不想就这个不相关的细节与 OP 争论。
【解决方案2】:

当然。为什么它不起作用?

boost::any::operator= 接受满足ValueType 的任何数据类型的参数。

boost::any 开始支持移动语义时,我会按值移动它,以便向前兼容。

template <typename T>
void Set(std::string optionName, T optionValue)
{
    OptionsMap[optionName] = std::move(optionValue);
}

向这个函数传递一个右值会在它可移动时移动它。这是标准保证的。

【讨论】:

  • 是的,但这是最有效/正确的方法吗?
  • @user3027108 如果不是,我为什么要推荐它?
  • @rightfold OP 提到 TT&amp;&amp;(通用参考)。您将其编写为通过值传递来强制复制
  • @NikosAthanasiou 这不是真的。传递一个右值会移动。按值并不意味着复制。它仅在传递左值时暗示复制,boost::any 进行复制/移动无论如何
  • @NikosAthanasiou 当参数的类型是可移动构造时,将右值传递给采用按值的函数将始终移动。复制省略无关紧要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多