完美转发和std :: tuple(或其他模板类)

时间:2011-11-25 17:38:43

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

我在完美转发方面遇到了一些困难。

这是我目前的理解水平:胶水模板+右值参考+ std :: forward和一个特殊的魔法模式被激活,其中模板扣除规则与通常的含义不同,但是精心设计以允许完美转发。示例:

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

但是如果T实际上是一个模板化的类会发生什么? 例如,我怎样才能完善std :: tuple?如果使用T&amp;&amp;因为我将丢失元组中包含的对象的所有类型信息 但是,以下代码无法运行:

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...>(); 
}

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

1 个答案:

答案 0 :(得分:3)

只有当参数的类型是函数的模板类型时,完美转发才有效,因此实现完美转发的唯一方法就像在第一个示例中一样:

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

以上情况有效,因为这是一个特殊情况,T被推断为SomeType&SomeType&&

但是,这并不意味着元组元素的类型信息会丢失。它仍然是可检索的(虽然我认为你不能键入一个可变参数模板包)。例如,您仍然可以像这样调用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可能更简单。)