【问题标题】:Perfect forwarding and std::tuple (or other templated class)完美转发和 std::tuple (或其他模板类)
【发布时间】:2012-01-06 12:51:56
【问题描述】:

完美转发有一些困难。

这是我目前的理解水平:胶水模板 + 右值引用 + std::forward 和一个特殊的神奇模式被激活,其中模板推导规则与通常的含义不同,但经过精心设计以允许完美转发。示例:

template <typename T>
void outer(T&& t)
{
   inner(std::forward<T>(t)); // perfect forwarding activated
}

但是如果 T 实际上是一个模板类会发生什么? 例如,如何完善转发 std::tuple ?如果使用 T&& 作为 aboce,我将丢失元组中包含的对象的所有类型信息。
但是下面的代码不能工作:

template <typename... Args>
void outer(std::tuple<Args...>&& t) 
{
   inner(std::forward<std::tuple<Args...>>(t));
   use_args_types_for_something_else<Args...>(); // I need to have Args available
}

int main()
{
   std::tuple<int, double, float> t(4, 5.0, 4.0f);
   outer(t);
}

最后一个 gcc 快照说:

error: cannot bind 'std::tuple<int, double, float> lvalue to
std::tuple<int, double, float>&&

很明显,我们仍然处于一般的、非模板的情况下,左值不能绑定到右值引用。 “完美转发模式”未开启

所以我试图偷偷摸摸,将我的元组作为模板模板传递:

template <
  typename... Args
  template <typename...> class T
>
void outer(T<Args...>&& t) 
{
   inner(std::forward<T<Args...>>(t));
   use_args_type_for_something_else<Args...>(); 
}

但我仍然遇到同样的错误。

【问题讨论】:

  • 不能直接调用std::forward而不指定类型吗(因为它是模板函数,可以使用推导)? std::forward(t)

标签: c++ templates c++11 tuples perfect-forwarding


【解决方案1】:

只有当参数的类型是函数的模板类型时,完美转发才有效,所以实现完美转发的唯一方法就像你的第一个例子:

template <typename T>
void outer(T&& t)
{
   inner(std::forward<T>(t)); // perfect forwarding activated
}

上述方法有效,因为这是一种特殊情况,T 被推导出为SomeType&amp;SomeType&amp;&amp;

然而,这并不意味着元组元素的类型信息会永远丢失。它仍然是可检索的(尽管我认为您不能 typedef 可变参数模板包)。例如,您仍然可以像这样调用use_args_types_for_something_else

template <class T>
struct call_uses_args;

template <class ...Args>
struct call_uses_args<std::tuple<Args...>>
{
    void call() const { use_args_types_for_something_else<Args...>(); }
};

template <typename TupleT>
void outer(TupleT&& t)
{
   inner(std::forward<TupleT>(t));
   call_uses_args<typename std::remove_reference<TupleT>::type>().call();
}

虽然可能没有好的通用解决方案,但希望这种情况很少见。 (例如,在这个特定示例中,重载 outer 可能更简单。)

【讨论】:

  • 感谢您准确而准确的回答。因此,关于 c++11 中的完美转发,我仍然感到有点不安,因为它如此依赖这个奇怪的组合“模板 + rref + std::forward”。它创建了一个小点,一般规则(如“右值引用仅绑定到右值”)不再适用。我想知道完美转发的一些特殊语法对于 c++11 是否会更好。无论如何,在这种情况下的解决方法确实没什么大不了的,因为仍然可以为outer 进行两个重载,一个使用 const ref,一个使用 rref 来模拟 PF。
猜你喜欢
  • 2015-04-11
  • 1970-01-01
  • 2015-09-07
  • 2016-03-22
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
相关资源
最近更新 更多