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

发布于 2024-12-18 05:14:32 字数 1249 浏览 2 评论 0原文

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

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

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

但是如果 T 实际上是模板类,会发生什么情况? 例如,如何完美转发 std::tuple ?如果使用 T&&首先,我将丢失元组中包含的对象的所有类型信息。
然而,以下代码无法工作:

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

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

I have some difficulties with perfect forwarding.

Here is my current level of understanding : glue Template + rvalue reference + std::forward and a special magical mode get activated where template deduction rules have not the same meaning as usual, but are crafted to allow perfect forwarding. Example :

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

But what happen if T is actually a templated class ?
For example, how can I perfect forward a std::tuple ? If use a T&& as aboce I will lost all type information of the objects contained in the tuple.
However the following code can't work :

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

Last gcc snapshot says :

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

So clearly, we are still in the general, non-template case where lvalue can't bind to rvalue reference. "Perfect forwading mode" is not activated

So I tried to be sneaky and pass my tuple as a template template :

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

But I still get the same error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

渡你暖光 2024-12-25 05:14:32

仅当参数的类型是函数的模板类型时,完美转发才起作用,因此实现完美转发的唯一方法就像第一个示例中所示:

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 可能会更简单。)

Perfect forwarding works only if the type of the parameter is a template type for the function, so the only way to achieve perfect forwarding is like in your first example:

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

The above works because it is a special case where T is deduced as SomeType& or SomeType&&.

This, however, does not mean that the type information for the tuple elements is lost for good. It is still retrievable (although I don't think you can typedef a variadic template pack). For example, you can still call use_args_types_for_something_else like this:

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

There might be no good general solution, though, but hopefully such situations are rare. (E.g, in this particular example, it might be simpler just to overload outer.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文