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

      1. <legend id='PHnZ3'><style id='PHnZ3'><dir id='PHnZ3'><q id='PHnZ3'></q></dir></style></legend><tfoot id='PHnZ3'></tfoot>

      2. <i id='PHnZ3'><tr id='PHnZ3'><dt id='PHnZ3'><q id='PHnZ3'><span id='PHnZ3'><b id='PHnZ3'><form id='PHnZ3'><ins id='PHnZ3'></ins><ul id='PHnZ3'></ul><sub id='PHnZ3'></sub></form><legend id='PHnZ3'></legend><bdo id='PHnZ3'><pre id='PHnZ3'><center id='PHnZ3'></center></pre></bdo></b><th id='PHnZ3'></th></span></q></dt></tr></i><div id='PHnZ3'><tfoot id='PHnZ3'></tfoot><dl id='PHnZ3'><fieldset id='PHnZ3'></fieldset></dl></div>
          <bdo id='PHnZ3'></bdo><ul id='PHnZ3'></ul>
      3. 将不可复制的闭包对象传递给 std::function 参数

        时间:2023-07-01
        <i id='IsLal'><tr id='IsLal'><dt id='IsLal'><q id='IsLal'><span id='IsLal'><b id='IsLal'><form id='IsLal'><ins id='IsLal'></ins><ul id='IsLal'></ul><sub id='IsLal'></sub></form><legend id='IsLal'></legend><bdo id='IsLal'><pre id='IsLal'><center id='IsLal'></center></pre></bdo></b><th id='IsLal'></th></span></q></dt></tr></i><div id='IsLal'><tfoot id='IsLal'></tfoot><dl id='IsLal'><fieldset id='IsLal'></fieldset></dl></div>

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

          <bdo id='IsLal'></bdo><ul id='IsLal'></ul>
          1. <tfoot id='IsLal'></tfoot>

                    <tbody id='IsLal'></tbody>

                  <legend id='IsLal'><style id='IsLal'><dir id='IsLal'><q id='IsLal'></q></dir></style></legend>
                  本文介绍了将不可复制的闭包对象传递给 std::function 参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  在 C++14 中,lambda 表达式可以通过使用捕获初始值设定项从变量中移动来捕获变量.然而,这使得生成的闭包对象不可复制.如果我有一个接受 std::function 参数的现有函数(我不能改变),我不能传递闭包对象,因为 std::function 的构造函数要求给定的函子是 CopyConstructible.

                  #include #include <内存>void doit(std::function f) {F();}int main(){std::unique_ptrp(new int(5));doit([p = std::move(p)] () { std::cout << *p << std::endl; });}

                  这会导致以下错误:

                  /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1911:10:错误:调用 '' 的隐式删除复制构造函数new _Functor(*__source._M_access<_Functor*>());^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1946:8: 注意:在成员函数'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>的实例化>::_M_clone' 在此处请求_M_clone(__dest, __source, _Local_storage());^/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2457:33: 注意:在成员函数'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>的实例化>::_M_manager' 在此处请求_M_manager = &_My_handler::_M_manager;^test.cpp:10:7: 注意:在函数模板特化的实例化中 'std::function::function<, void>'在这里请求doit([p = std::move(p)] () { std::cout << *p << std::endl; });^test.cpp:10:8: 注意:'' 的复制构造函数被隐式删除,因为字段 '' 已删除复制构造函数doit([p = std::move(p)] () { std::cout << *p << std::endl; });^/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/unique_ptr.h:273:7:注意:'unique_ptr' 已在此处明确标记为已删除unique_ptr(const unique_ptr&) = 删除;^

                  是否有合理的解决方法?

                  使用 Ubuntu clang 版本 3.5-1~exp1 (trunk) 进行测试

                  解决方案

                  有这个办法:

                  模板<类型名称签名>struct make_copyable_function_helper;模板<类型名称 R,类型名称... Args >struct make_copyable_function_helper<R(Args...)>{模板<类型名输入>std::function<R(Args...)>运算符()(输入&& i)const {自动 ptr = std::make_shared::type >( std::forward(i) );返回 [ptr]( Args... args )->R {返回 (*ptr)(std::forward(args)...);};}};模板make_copyable_function(输入&& i){return make_copyable_function_helper()( std::forward(i) );}

                  在这里我们创建一个指向我们数据的共享指针,然后创建一个捕获该共享指针的可复制 lambda,然后我们将该可复制 lambda 包装到请求签名的 std::function 中.>

                  在上述情况下,您只需:

                  doit( make_copyable_function( [p = std::move(p)] () { std::cout << *p << std::endl; }) );

                  稍微高级的版本推迟了类型擦除并添加了一层完美转发以减少开销:

                  templatestruct copyable_function {typedef typename std::decay::type stored_input;模板自动操作符()(Args&&...args)->decltype( std::declval()(std::forward(args)...)){返回 (*ptr)(std::forward(args));}copyable_function( input&& i ):ptr( std::make_shared( std::forward(i) ) ) {}copyable_function( copyable_function const& ) = default;私人的:std::shared_ptr指针;};模板<类型名输入>copyable_function<输入>make_copyable_function(输入&& i){返回 {std::forward(i)};}

                  它不需要您传入签名,并且在某些情况下效率会更高一些,但使用的技术更加晦涩.

                  在 C++14 中可以更简洁:

                  模板( std::forward(f) );返回 [spf](auto&&... args)->decltype(auto) {返回 (*spf)( decltype(args)(args)...);};}

                  完全不需要辅助类型.

                  In C++14, a lambda expression can capture variables by moving from them using capture initializers. However, this makes the resulting closure object non-copyable. If I have an existing function that takes a std::function argument (that I cannot change), I cannot pass the closure object, because std::function's constructor requires the given functor to be CopyConstructible.

                  #include <iostream>
                  #include <memory>
                  
                  void doit(std::function<void()> f) {
                      f();
                  }
                  
                  int main()
                  {
                      std::unique_ptr<int> p(new int(5));
                      doit([p = std::move(p)] () { std::cout << *p << std::endl; });
                  }
                  

                  This gives the following errors:

                  /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1911:10: error: 
                        call to implicitly-deleted copy constructor of '<lambda at test.cpp:10:7>'
                              new _Functor(*__source._M_access<_Functor*>());
                                  ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1946:8: note: in
                        instantiation of member function 'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>
                        >::_M_clone' requested here
                                _M_clone(__dest, __source, _Local_storage());
                                ^
                  /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2457:33: note: in
                        instantiation of member function 'std::_Function_base::_Base_manager<<lambda at test.cpp:10:7>
                        >::_M_manager' requested here
                              _M_manager = &_My_handler::_M_manager;
                                                         ^
                  test.cpp:10:7: note: in instantiation of function template specialization 'std::function<void
                        ()>::function<<lambda at test.cpp:10:7>, void>' requested here
                          doit([p = std::move(p)] () { std::cout << *p << std::endl; });
                               ^
                  test.cpp:10:8: note: copy constructor of '' is implicitly deleted because field '' has a deleted
                        copy constructor
                          doit([p = std::move(p)] () { std::cout << *p << std::endl; });
                                ^
                  /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/unique_ptr.h:273:7: note: 
                        'unique_ptr' has been explicitly marked deleted here
                        unique_ptr(const unique_ptr&) = delete;
                        ^
                  

                  Is there a reasonable workaround?

                  Testing with Ubuntu clang version 3.5-1~exp1 (trunk)

                  解决方案

                  There is this approach:

                  template< typename signature >
                  struct make_copyable_function_helper;
                  template< typename R, typename... Args >
                  struct make_copyable_function_helper<R(Args...)> {
                    template<typename input>
                    std::function<R(Args...)> operator()( input&& i ) const {
                      auto ptr = std::make_shared< typename std::decay<input>::type >( std::forward<input>(i) );
                      return [ptr]( Args... args )->R {
                        return (*ptr)(std::forward<Args>(args)...);
                      };
                    }
                  };
                  
                  template< typename signature, typename input >
                  std::function<signature> make_copyable_function( input && i ) {
                    return make_copyable_function_helper<signature>()( std::forward<input>(i) );
                  }
                  

                  where we make a shared pointer to our data, then make a copyable lambda that captures that shared pointer, then we wrap that copyable lambda into a std::function of the requested signature.

                  In your case above, you'd just:

                  doit( make_copyable_function<void()>( [p = std::move(p)] () { std::cout << *p << std::endl; } ) );
                  

                  A slightly more advanced version defers the type erasure and adds a layer of perfect forwarding to reduce overhead:

                  template<typename input>
                  struct copyable_function {
                    typedef typename std::decay<input>::type stored_input;
                    template<typename... Args>
                    auto operator()( Args&&... args )->
                      decltype( std::declval<input&>()(std::forward<Args>(args)...) )
                    {
                      return (*ptr)(std::forward<Args>(args));
                    }
                    copyable_function( input&& i ):ptr( std::make_shared<stored_input>( std::forward<input>(i) ) ) {}
                    copyable_function( copyable_function const& ) = default;
                  private:
                    std::shared_ptr<stored_input> ptr;
                  };
                  template<typename input>
                  copyable_function<input> make_copyable_function( input&& i ) {
                    return {std::forward<input>(i)}; 
                  }
                  

                  which does not require you to pass the signature in, and can be slightly more efficient in a few cases, but uses more obscure techniques.

                  In C++14 with this can be made even more brief:

                  template< class F >
                  auto make_copyable_function( F&& f ) {
                    using dF=std::decay_t<F>;
                    auto spf = std::make_shared<dF>( std::forward<F>(f) );
                    return [spf](auto&&... args)->decltype(auto) {
                      return (*spf)( decltype(args)(args)... );
                    };
                  }
                  

                  doing away with the need for the helper type entirely.

                  这篇关于将不可复制的闭包对象传递给 std::function 参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:时间:2019-05-06 标签:c++find_iflambda 下一篇:我们可以使用 lambda 表达式作为函数参数的默认值吗?

                  相关文章

                    <bdo id='GINLg'></bdo><ul id='GINLg'></ul>

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

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