Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble move-capturing std::unique_ptr in a lambda using std::bind

I'd like to capture a variable of type std::vector<std::unique_ptr<MyClass>> in a lambda expression (in other words, "capture by move"). I found a solution which uses std::bind to capture unique_ptr (https://stackoverflow.com/a/12744730/2478832) and decided to use it as a starting point. However, the most simplified version of the proposed code I could get doesn't compile (lots of template mistakes, it seems to try to call unique_ptr's copy constructor).

#include <functional>
#include <memory>

std::function<void ()> a(std::unique_ptr<int>&& param)
{
    return std::bind( [] (int* p) {},
        std::move(param));
}

int main()
{
    a(std::unique_ptr<int>(new int()));
}

Can anybody point out what is wrong with this code?

EDIT: tried changing the lambda to take a reference to unique_ptr, it still doesn't compile.

#include <functional>
#include <memory>

std::function<void ()> a(std::unique_ptr<int>&& param)
{
    return std::bind( [] (std::unique_ptr<int>& p) {}, // also as a const reference
        std::move(param));
}

int main()
{
    a(std::unique_ptr<int>(new int()));
}

Here's Visual Studio 2012 output:

1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\tuple(151): error C2248: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<int,std::default_delete<_Ty>>'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1447) : see declaration of 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\tuple(521) : see reference to function template instantiation 'std::_Tuple_val<_This>::_Tuple_val<const _Ty&>(_Other)' being compiled
1>          with
1>          [
1>              _This=std::unique_ptr<int,std::default_delete<int>>
1>  ,            _Ty=std::unique_ptr<int,std::default_delete<int>>
1>  ,            _Other=const std::unique_ptr<int,std::default_delete<int>> &
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\tuple(521) : see reference to function template instantiation 'std::_Tuple_val<_This>::_Tuple_val<const _Ty&>(_Other)' being compiled
1>          with
1>          [
1>              _This=std::unique_ptr<int,std::default_delete<int>>
1>  ,            _Ty=std::unique_ptr<int,std::default_delete<int>>
1>  ,            _Other=const std::unique_ptr<int,std::default_delete<int>> &
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\tuple(521) : while compiling class template member function 'std::tuple<std::unique_ptr<int,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::tuple(const std::tuple<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> &)'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\functional(1152) : see reference to function template instantiation 'std::tuple<std::unique_ptr<int,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::tuple(const std::tuple<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> &)' being compiled
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\functional(1152) : see reference to class template instantiation 'std::tuple<std::unique_ptr<int,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>' being compiled
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          main.cpp(15) : see reference to class template instantiation 'std::_Bind<false,void,a::<lambda_2ad08ede4c4ce9c02d5497417b633d1d>,std::unique_ptr<int,std::default_delete<_Ty>>,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>' being compiled
1>          with
1>          [
1>              _Ty=int
1>          ]
like image 793
user2478832 Avatar asked May 14 '26 16:05

user2478832


2 Answers

The second argument to bind will be passed to the bound object at the time of call. The problem is that the lambda takes a int*, but the argument is a std::unique_ptr<int> and there is no conversion from the latter to the former.

It should compile (untested) if you change the signature of the lambda to take a std::unique_ptr by reference/const-reference

like image 82
David Rodríguez - dribeas Avatar answered May 17 '26 08:05

David Rodríguez - dribeas


The problem with the version that passes a lambda taking unique_ptr by reference to std::bind is your conversion to std::function - std::function requires functions to be CopyConstructible ([func.wrap.func.con] p7). Try it without the std::function (Live at ideone):

auto f = std::bind([](std::unique_ptr<int>&){},
                   std::make_unique<int>());
like image 27
Casey Avatar answered May 17 '26 07:05

Casey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!