• <tfoot id='z78Mw'></tfoot>
    1. <i id='z78Mw'><tr id='z78Mw'><dt id='z78Mw'><q id='z78Mw'><span id='z78Mw'><b id='z78Mw'><form id='z78Mw'><ins id='z78Mw'></ins><ul id='z78Mw'></ul><sub id='z78Mw'></sub></form><legend id='z78Mw'></legend><bdo id='z78Mw'><pre id='z78Mw'><center id='z78Mw'></center></pre></bdo></b><th id='z78Mw'></th></span></q></dt></tr></i><div id='z78Mw'><tfoot id='z78Mw'></tfoot><dl id='z78Mw'><fieldset id='z78Mw'></fieldset></dl></div>

      1. <small id='z78Mw'></small><noframes id='z78Mw'>

        <legend id='z78Mw'><style id='z78Mw'><dir id='z78Mw'><q id='z78Mw'></q></dir></style></legend>
          <bdo id='z78Mw'></bdo><ul id='z78Mw'></ul>

        c++ lambdas 如何从上层范围捕获可变参数包

        时间:2023-06-30
        <tfoot id='6sA3M'></tfoot>

        <small id='6sA3M'></small><noframes id='6sA3M'>

          <i id='6sA3M'><tr id='6sA3M'><dt id='6sA3M'><q id='6sA3M'><span id='6sA3M'><b id='6sA3M'><form id='6sA3M'><ins id='6sA3M'></ins><ul id='6sA3M'></ul><sub id='6sA3M'></sub></form><legend id='6sA3M'></legend><bdo id='6sA3M'><pre id='6sA3M'><center id='6sA3M'></center></pre></bdo></b><th id='6sA3M'></th></span></q></dt></tr></i><div id='6sA3M'><tfoot id='6sA3M'></tfoot><dl id='6sA3M'><fieldset id='6sA3M'></fieldset></dl></div>

            <legend id='6sA3M'><style id='6sA3M'><dir id='6sA3M'><q id='6sA3M'></q></dir></style></legend>
              <bdo id='6sA3M'></bdo><ul id='6sA3M'></ul>
                    <tbody id='6sA3M'></tbody>
                  本文介绍了c++ lambdas 如何从上层范围捕获可变参数包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我研究了通用 lambda 表达式,并稍微修改了示例,所以我的 lambda 应该捕获上层 lambda 的可变参数包.所以基本上什么是给上层 lambda 的 (auto&&...) - 应该以某种方式在 [=] 块中捕获.

                  I study the generic lambdas, and slightly modified the example, so my lambda should capture the upper lambda's variadic parameter pack. So basically what is given to upper lambda as (auto&&...) - should be somehow captured in [=] block.

                  (完美转发是另一个问题,我很好奇这里有可能吗?)

                  (The perfect forwarding is another question, I'm curious is it possible here at all?)

                  #include <iostream>
                  #include<type_traits>
                  #include<utility>
                  
                  
                  // base case
                  void doPrint(std::ostream& out) {}
                  
                  template <typename T, typename... Args>
                  void doPrint(std::ostream& out, T && t, Args && ... args)
                  {
                      out << t << " ";                // add comma here, see below
                      doPrint(out, std::forward<Args&&>(args)...);
                  }
                  
                  int main()
                  {
                      // generic lambda, operator() is a template with one parameter
                      auto vglambda = [](auto printer) {
                          return [=](auto&&... ts) // generic lambda, ts is a parameter pack
                          {
                              printer(std::forward<decltype(ts)>(ts)...);
                              return [=] {  // HOW TO capture the variadic ts to be accessible HERE ↓
                                  printer(std::forward<decltype(ts)>(ts)...); // ERROR: no matchin function call to forward
                              }; // nullary lambda (takes no parameters)
                          };
                      };
                      auto p = vglambda([](auto&&...vars) {
                          doPrint(std::cout, std::forward<decltype(vars)>(vars)...);
                      });
                      auto q = p(1, 'a', 3.14,5); // outputs 1a3.14
                  
                      //q(); //use the returned lambda "printer"
                  
                  }
                  

                  推荐答案

                  C++20 中的完美捕获

                  template <typename ... Args>
                  auto f(Args&& ... args){
                      return [... args = std::forward<Args>(args)]{
                          // use args
                      };
                  }
                  

                  <小时>

                  C++17 和 C++14 解决方法

                  在 C++17 中,我们可以使用元组的解决方法:

                  In C++17 we can use a workaround with tuples:

                  template <typename ... Args>
                  auto f(Args&& ... args){
                      return [args = std::make_tuple(std::forward<Args>(args) ...)]()mutable{
                          return std::apply([](auto&& ... args){
                              // use args
                          }, std::move(args));
                      };
                  }
                  

                  不幸的是 std::apply 是 C++17,在 C++14 中你可以自己实现它或者用 boost::hana 做类似的事情:>

                  Unfortunately std::apply is C++17, in C++14 you can implement it yourself or do something similar with boost::hana:

                  namespace hana = boost::hana;
                  
                  template <typename ... Args>
                  auto f(Args&& ... args){
                      return [args = hana::make_tuple(std::forward<Args>(args) ...)]()mutable{
                          return hana::unpack(std::move(args), [](auto&& ... args){
                              // use args
                          });
                      };
                  }
                  

                  通过函数capture_call来简化解决方法可能会很有用:

                  It might be usefull to simplify the workaround by a function capture_call:

                  #include <tuple>
                  
                  // Capture args and add them as additional arguments
                  template <typename Lambda, typename ... Args>
                  auto capture_call(Lambda&& lambda, Args&& ... args){
                      return [
                          lambda = std::forward<Lambda>(lambda),
                          capture_args = std::make_tuple(std::forward<Args>(args) ...)
                      ](auto&& ... original_args)mutable{
                          return std::apply([&lambda](auto&& ... args){
                              lambda(std::forward<decltype(args)>(args) ...);
                          }, std::tuple_cat(
                              std::forward_as_tuple(original_args ...),
                              std::apply([](auto&& ... args){
                                  return std::forward_as_tuple< Args ... >(
                                      std::move(args) ...);
                              }, std::move(capture_args))
                          ));
                      };
                  }
                  

                  像这样使用它:

                  #include <iostream>
                  
                  // returns a callable object without parameters
                  template <typename ... Args>
                  auto f1(Args&& ... args){
                      return capture_call([](auto&& ... args){
                          // args are perfect captured here
                          // print captured args via C++17 fold expression
                          (std::cout << ... << args) << '
                  ';
                      }, std::forward<Args>(args) ...);
                  }
                  
                  // returns a callable object with two int parameters
                  template <typename ... Args>
                  auto f2(Args&& ... args){
                      return capture_call([](int param1, int param2, auto&& ... args){
                          // args are perfect captured here
                          std::cout << param1 << param2;
                          (std::cout << ... << args) << '
                  ';
                      }, std::forward<Args>(args) ...);
                  }
                  
                  int main(){
                      f1(1, 2, 3)();     // Call lambda without arguments
                      f2(3, 4, 5)(1, 2); // Call lambda with 2 int arguments
                  }
                  

                  <小时>

                  这是capture_call的C++14实现:

                  #include <tuple>
                  
                  // Implementation detail of a simplified std::apply from C++17
                  template < typename F, typename Tuple, std::size_t ... I >
                  constexpr decltype(auto)
                  apply_impl(F&& f, Tuple&& t, std::index_sequence< I ... >){
                      return static_cast< F&& >(f)(std::get< I >(static_cast< Tuple&& >(t)) ...);
                  }
                  
                  // Implementation of a simplified std::apply from C++17
                  template < typename F, typename Tuple >
                  constexpr decltype(auto) apply(F&& f, Tuple&& t){
                      return apply_impl(
                          static_cast< F&& >(f), static_cast< Tuple&& >(t),
                          std::make_index_sequence< std::tuple_size<
                              std::remove_reference_t< Tuple > >::value >{});
                  }
                  
                  // Capture args and add them as additional arguments
                  template <typename Lambda, typename ... Args>
                  auto capture_call(Lambda&& lambda, Args&& ... args){
                      return [
                          lambda = std::forward<Lambda>(lambda),
                          capture_args = std::make_tuple(std::forward<Args>(args) ...)
                      ](auto&& ... original_args)mutable{
                          return ::apply([&lambda](auto&& ... args){
                              lambda(std::forward<decltype(args)>(args) ...);
                          }, std::tuple_cat(
                              std::forward_as_tuple(original_args ...),
                              ::apply([](auto&& ... args){
                                  return std::forward_as_tuple< Args ... >(
                                      std::move(args) ...);
                              }, std::move(capture_args))
                          ));
                      };
                  }
                  

                  <小时>

                  capture_call 按值捕获变量.完美意味着尽可能使用移动构造函数.下面是一个 C++17 代码示例,以便更好地理解:


                  capture_call captures variables by value. The perfect means that the move constructor is used if possible. Here is a C++17 code example for better understanding:

                  #include <tuple>
                  #include <iostream>
                  #include <boost/type_index.hpp>
                  
                  
                  // Capture args and add them as additional arguments
                  template <typename Lambda, typename ... Args>
                  auto capture_call(Lambda&& lambda, Args&& ... args){
                      return [
                          lambda = std::forward<Lambda>(lambda),
                          capture_args = std::make_tuple(std::forward<Args>(args) ...)
                      ](auto&& ... original_args)mutable{
                          return std::apply([&lambda](auto&& ... args){
                              lambda(std::forward<decltype(args)>(args) ...);
                          }, std::tuple_cat(
                              std::forward_as_tuple(original_args ...),
                              std::apply([](auto&& ... args){
                                  return std::forward_as_tuple< Args ... >(
                                      std::move(args) ...);
                              }, std::move(capture_args))
                          ));
                      };
                  }
                  
                  struct A{
                      A(){
                          std::cout << "  A::A()
                  ";
                      }
                  
                      A(A const&){
                          std::cout << "  A::A(A const&)
                  ";
                      }
                  
                      A(A&&){
                          std::cout << "  A::A(A&&)
                  ";
                      }
                  
                      ~A(){
                          std::cout << "  A::~A()
                  ";
                      }
                  };
                  
                  int main(){
                      using boost::typeindex::type_id_with_cvr;
                  
                      A a;
                      std::cout << "create object end
                  
                  ";
                  
                      [b = a]{
                          std::cout << "  type of the capture value: "
                            << type_id_with_cvr<decltype(b)>().pretty_name()
                            << "
                  ";
                      }();
                      std::cout << "value capture end
                  
                  ";
                  
                      [&b = a]{
                          std::cout << "  type of the capture value: "
                            << type_id_with_cvr<decltype(b)>().pretty_name()
                            << "
                  ";
                      }();
                      std::cout << "reference capture end
                  
                  ";
                  
                      [b = std::move(a)]{
                          std::cout << "  type of the capture value: "
                            << type_id_with_cvr<decltype(b)>().pretty_name()
                            << "
                  ";
                      }();
                      std::cout << "perfect capture end
                  
                  ";
                  
                      [b = std::move(a)]()mutable{
                          std::cout << "  type of the capture value: "
                            << type_id_with_cvr<decltype(b)>().pretty_name()
                            << "
                  ";
                      }();
                      std::cout << "perfect capture mutable lambda end
                  
                  ";
                  
                      capture_call([](auto&& b){
                          std::cout << "  type of the capture value: "
                            << type_id_with_cvr<decltype(b)>().pretty_name()
                            << "
                  ";
                      }, std::move(a))();
                      std::cout << "capture_call perfect capture end
                  
                  ";
                  }
                  

                  输出:

                    A::A()
                  create object end
                  
                    A::A(A const&)
                    type of the capture value: A const
                    A::~A()
                  value capture end
                  
                    type of the capture value: A&
                  reference capture end
                  
                    A::A(A&&)
                    type of the capture value: A const
                    A::~A()
                  perfect capture end
                  
                    A::A(A&&)
                    type of the capture value: A
                    A::~A()
                  perfect capture mutable lambda end
                  
                    A::A(A&&)
                    type of the capture value: A&&
                    A::~A()
                  capture_call perfect capture end
                  
                    A::~A()
                  

                  捕获值的类型在capture_call版本中包含&&,因为我们必须通过引用访问内部元组中的值,而支持的语言capture 支持直接访问值.

                  The type of the capture value contains && in the capture_call version because we have to access the value in the internal tuple via reference, while a language supported capture supports direct access to the value.

                  这篇关于c++ lambdas 如何从上层范围捕获可变参数包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:C++14 中的递归 lambda 函数 下一篇:Lambda 函数作为基类

                  相关文章

                  <small id='LBVdN'></small><noframes id='LBVdN'>

                    • <bdo id='LBVdN'></bdo><ul id='LBVdN'></ul>

                      <tfoot id='LBVdN'></tfoot><legend id='LBVdN'><style id='LBVdN'><dir id='LBVdN'><q id='LBVdN'></q></dir></style></legend>

                      <i id='LBVdN'><tr id='LBVdN'><dt id='LBVdN'><q id='LBVdN'><span id='LBVdN'><b id='LBVdN'><form id='LBVdN'><ins id='LBVdN'></ins><ul id='LBVdN'></ul><sub id='LBVdN'></sub></form><legend id='LBVdN'></legend><bdo id='LBVdN'><pre id='LBVdN'><center id='LBVdN'></center></pre></bdo></b><th id='LBVdN'></th></span></q></dt></tr></i><div id='LBVdN'><tfoot id='LBVdN'></tfoot><dl id='LBVdN'><fieldset id='LBVdN'></fieldset></dl></div>