gpt4 book ai didi

c++ - 将不可复制的闭包对象传递给 std::function 参数

转载 作者:行者123 更新时间:2023-12-02 10:33:02 27 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





How to create an std::function from a move-capturing lambda expression?

(3 个回答)


1年前关闭。




在 C++14 中,lambda 表达式可以通过使用捕获初始化程序从变量中 move 来捕获变量。但是,这使得生成的闭包对象不可复制。如果我有一个采用 std::function 的现有函数参数(我无法更改),我无法传递闭包对象,因为 std::function的构造函数要求给定的仿函数是 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; });
}

这会产生以下错误:
/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;
^

有没有合理的解决方法?

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

最佳答案

有这种方法:

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

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

在上述情况下,您只需:
doit( make_copyable_function<void()>( [p = std::move(p)] () { std::cout << *p << std::endl; } ) );

稍微高级一点的版本推迟了类型删除,并添加了一层完美转发以减少开销:
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)};
}

它不需要您传递签名,并且在某些情况下可能会稍微更有效,但使用更晦涩的技术。

在 C++14 中,这可以变得更简洁:
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)... );
};
}

完全不需要辅助类型。

关于c++ - 将不可复制的闭包对象传递给 std::function 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61562719/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com