How to return std :: a function that contains std :: unique_ptr from a generic lambda capture in C ++ 14?

How do we return a std::function that contains std::unique_ptr from a generic lambda capture in C ++ 14? In particular, in the following code

 // For std::function #include <functional> // For std::iostream #include <iostream> // For std::unique_ptr #include <memory> #if 0 std::function <void()> make_foo() { auto x = std::make_unique <int> (3); return [x=std::move(x)]() { std::cout << *x << std::endl; }; } #endif int main() { auto x = std::make_unique <int> (3); auto foo = [x=std::move(x)]() { std::cout << *x << std::endl; }; foo(); } 

Everything works fine at startup with GCC 4.9.2 and C ++ 14 enabled. In particular, this shows that generalized lambda captures work. However, when we change the code where #if 1 , we get a compilation error:

 g++ -g -std=c++14 test01.cpp -o test01 In file included from test01.cpp:4:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional: In instantiation of 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = make_foo()::<lambda()>; std::false_type = std::integral_constant<bool, false>]': /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:1914:51: required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = make_foo()::<lambda()>]' /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2428:19: required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = make_foo()::<lambda()>; <template-parameter-2-2> = void; _Res = void; _ArgTypes = {}]' test01.cpp:17:5: required from here /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:1878:34: error: use of deleted function 'make_foo()::<lambda()>::<lambda>(const make_foo()::<lambda()>&)' __dest._M_access<_Functor*>() = ^ test01.cpp:15:27: note: 'make_foo()::<lambda()>::<lambda>(const make_foo()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed: return [x=std::move(x)]() { ^ test01.cpp:15:27: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]' In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/memory:81:0, from test01.cpp:10: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/bits/unique_ptr.h:356:7: note: declared here unique_ptr(const unique_ptr&) = delete; ^ Makefile:2: recipe for target 'all' failed make: *** [all] Error 1 

Now, given that the returned function contains std::unique_ptr , it makes sense that we cannot copy the resulting std::function . However, since we are returning the lambda function created on the fly, should this not be the r-value and the correct definition? Basically, is there a way to fix make_foo where we still have a generic lambda capture of a std::unique_ptr ?

+5
source share
2 answers

As @TC says in the comments, std::function requires the caller to wrap CopyConstructible, and your lambda is not associated with the unique_ptr data unique_ptr .

You can use C ++ 14 return type inference for functions that return lambdas from make_foo and avoid wrapping it in std::function .

 auto make_foo() { auto x = std::make_unique <int> (3); return [x=std::move(x)]() { std::cout << *x << std::endl; }; } make_foo()(); // prints 3 

Live demo

+5
source

std::function uselessly copied (how often do you want to copy std::function ?). Due to the erasing of styles, the fact that you can copy std::function means that the material you store in std::function must be copied even if you do not!

You can easily implement moving only std::function . Getting a good QOI is more difficult - SFO (optimization of small functions), like SSO (optimization of small lines), would be a good idea to avoid useless heap allocation.

here is a sketch just for moving std::function called task . He does not have SFO.

This is only necessary if you need to save the resulting lambda in the type-not-connected code to the code generating the lambda. If you don’t need to do this, you can return auto and publish your implementation and let you deduce the return type of the C ++ 14 type for you.

+3
source

All Articles