完善的函数转发构建函数列表类 [英] Perfect forwarding of functions to build a function list class

查看:134
本文介绍了完善的函数转发构建函数列表类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  //函数列表类
模板< p>类... F>
struct function_list
{
template< class ... G>
constexpr function_list(G&& g)noexcept
:_f {std :: forward< G>(g)...}
{
}
std :: tuple< / * F ... OR F&& ... * /> _F;
};

//函数列表生成器
模板< class ... F,class R = / *我们可以在这里计算返回类型吗? * />
constexpr R make_function_list(F&& ... f)
{
return function_list<
/ * decltype(std :: forward< F>(f))...
* OR F ...
* OR F&& ...
* />(标准::向前< f是氟烃基;(F)...);
}

我希望这些函数能够完美转发(不管它们是否为函数指针,函子,lambdas ...)。但我不完全理解 std :: forward 和通用引用背后发生的所有类型扣除。在上面的代码中,我有三个问题:


  • 如果 _f 是类型 std :: tuple< F ...> std :: tuple< F&&> (为什么?)

  • 是否有可能在模板参数列表中推导出返回类型 R 而不是 auto / decltype(auto)将有助于理解发生了什么)

  • 在制造商中, function_list 模板参数应该是: decltype(std :: forward< F>(f)...) F F&& ... (以及为什么?)



注意: function_list 的构造函数不是直接调用,而是 make_function_list

编辑:
运算符() function_list (这里没有显示)不保证在同一个语句上被调用?

 模板< class ... F> 
constexpr function_list< F ...> make_function_list(F& amp; ... f)
{
return function_list< F& amp;>(std :: forward< F>(f)...);
}


解决方案


但我不完全理解 std :: forward 和通用引用背后发生的所有类型推演。


通过一个例子很容易理解。

 模板< typename T> 
void f(T&);
{
std :: tuple< T> {}; //(0)
std :: tuple< T&&> {}; // <1>

如果(0)


  • T 推断为 T对于 rvalues

  • T 被推断为 T& for 左值

  • 1):


    • T 推断为 T&& for rvalues

    • T T& 左值
    • 可以看到,两者之间的唯一区别是如何推导出 rvalues

      关于 std :: forward

      c $ c>,这就是它的作用:

       模板< typename T> 
      void g(T&& amp;);

      模板< typename T>
      void f(T& x)
      {
      g(x)//(0)
      g(std :: forward< T>(x)); // <1>

      如果(0)


      • x 总是一个左值 >。



      对于(1)


      • x 被转换为 T&& if T 推断为 T


      • x 保留一个左值,否则。




      通过查看 std :: forward 基本上保留了 x 的类型类别。 T
      被推断出来。







      code> std :: tuple< F ...> std :: tuple< F&& ...>


      我认为在你的情况下应该是 std :: tuple< F ...> ,因为您要存储左值引用

      的std ::元组< F&安培;& amp; ...> 会存储左值引用右值引用 - 这会导致悬空引用在临时情况下。





      是否可以推导出返回类型<$ c

      是的,它只是在模板参数列表中$ c> R function_list< F的>

       模板< class ... F,class R = function_list< F ...>> 
      constexpr R make_function_list(F& ... f)
      {
      return function_list< F ...>(std :: forward< F>(f)...) ;

      $ / code>

      你甚至不需要 R 模板参数。

       模板< class ... F> 
      constexpr function_list< F ...> make_function_list(F& ... f)
      {
      return function_list< F ...>(std :: forward< F>(f)...);
      }







      <在制造商中, function_list 模板参数应该是: decltype(std :: forward< F>(f)...) F F&< / code>




      function_list 应该取 F ... as一个模板参数,用于回答开头列出的原因(即避免对临时对象的悬挂引用)



      它仍然需要 std :: forward< F>(f)... 作为它的参数来允许 rvalues function_list 的元组)

      Consider the following code that build a class storing functions.

      // Function list class
      template <class... F>
      struct function_list
      {
          template <class... G>
          constexpr function_list(G&&... g) noexcept
          : _f{std::forward<G>(g)...}
          {
          }
          std::tuple</* F... OR F&&... */> _f;
      };
      
      // Function list maker
      template <class... F, class R = /* Can we compute the return type here? */>
      constexpr R make_function_list(F&&... f)
      {
          return function_list<
              /* decltype(std::forward<F>(f))...
               * OR F...
               * OR F&&...
              */>(std::forward<F>(f)...);
      }
      

      I would like these functions to be perfectly forwarded (regardless of whether they are function pointers, functors, lambdas...). But I don't exactly understand all the type deduction happening behind std::forward and universal references. In the code above, I have three questions:

      • Should _f be of type std::tuple<F...> or std::tuple<F&&...> (and why?)
      • Is it possible to deduce the return type R in the template parameter list (because doing it manually instead of auto/decltype(auto) would be helpful to understand what is going on)
      • In the maker, what the function_list template argument should be: decltype(std::forward<F>(f)...), F, or F&&... (and why?)

      Note: the constructor of function_list is not meant to be called directly, instead make_function_list is doing the job.

      EDIT: Is this case safe, when the operator() of function_list (not shown here) is not guaranted to be called on the same statement?

      template <class... F>
      constexpr function_list<F...> make_function_list(F&&... f)
      {
          return function_list<F&&...>(std::forward<F>(f)...);
      }
      

      解决方案

      But I don't exactly understand all the type deduction happening behind std::forward and universal references.

      It's quite simple to understand via an example.

      template <typename T>
      void f(T&&)
      {
          std::tuple<T>{}; // (0)
          std::tuple<T&&>{}; // (1)
      }
      

      In the case of (0):

      • T is deduced as T for rvalues
      • T is deduced as T& for lvalues.

      In the case of (1):

      • T is deduced as T&& for rvalues
      • T is deduced as T& for lvalues.

      As you can see, the only difference between two is how rvalues are deduced.

      Regarding std::forward, this is what it does:

      template <typename T>
      void g(T&&);
      
      template <typename T>
      void f(T&& x)
      {
          g(x) // (0)
          g(std::forward<T>(x)); // (1)
      }
      

      In the case of (0):

      • x is always an lvalue.

      In the case of (1):

      • x is casted to T&& if T is deduced as T.

      • x stays an lvalue otherwise.

      std::forward basically retains the type category of x by looking at how T was deduced.


      Should _f be of type std::tuple<F...> or std::tuple<F&&...>

      I think that in your case it should be std::tuple<F...>, as you want to store either lvalue references or values.

      std::tuple<F&&...> would store either lvalue references or rvalue references - that would lead to dangling references in the case of temporaries.


      Is it possible to deduce the return type R in the template parameter list

      Yes, it is just function_list<F...>.

      template <class... F, class R = function_list<F...>>
      constexpr R make_function_list(F&&... f)
      {
          return function_list<F...>(std::forward<F>(f)...);
      }
      

      You don't even need the R template parameter.

      template <class... F>
      constexpr function_list<F...> make_function_list(F&&... f)
      {
          return function_list<F...>(std::forward<F>(f)...);
      }
      


      In the maker, what the function_list template argument should be: decltype(std::forward<F>(f)...), F, or F&&...

      function_list should take F... as a template parameter for the reasons listed at the beginning of this answer (i.e. avoiding dangling references to temporaries).

      It should still take std::forward<F>(f)... as its arguments to allow rvalues to be forwarded as such (i.e. moving rvalues into function_list's tuple).

      这篇关于完善的函数转发构建函数列表类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆