Como capturar um unique_ptr em uma expressão lambda?

Eu tentei o seguinte:

std::function getAction(std::unique_ptr &&psomething){ //The caller given ownership of psomething return [psomething](){ psomething->do_some_thing(); //psomething is expected to be released after this point }; } 

Mas não compila. Alguma ideia?

ATUALIZAR:

Como sugerido, alguma nova syntax é necessária para especificar explicitamente que precisamos transferir a propriedade para o lambda, agora estou pensando sobre a seguinte syntax:

 std::function getAction(std::unique_ptr psomething){ //The caller given ownership of psomething return [auto psomething=move(psomething)](){ psomething->do_some_thing(); //psomething is expected to be released after this point }; } 

Seria um bom candidato?

ATUALIZAÇÃO 1:

Vou mostrar minha implementação de move e copy seguinte forma:

 template T copy(const T &t) { return t; } //process lvalue references template T move(T &t) { return std::move(t); } class A{/*...*/}; void test(A &&a); int main(int, char **){ A a; test(copy(a)); //OK, copied test(move(a)); //OK, moved test(A()); //OK, temporary object test(copy(A())); //OK, copying temporary object //You can disable this behavior by letting copy accepts T & //test(move(A())); You should never move a temporary object //It is not good to have a rvalue version of move. //test(a); forbidden, you have to say weather you want to copy or move //from a lvalue reference. } 

Esse problema é tratado pela captura generalizada lambda no C ++ 14:

 // a unique_ptr is move-only auto u = make_unique(some, parameters); // move the unique_ptr into the lambda go.run([u = move(u)]{do_something_with(u);}); 

Você não pode capturar permanentemente um unique_ptr em um lambda. De fato, se você quiser capturar permanentemente qualquer coisa em um lambda, ele deve ser copiável ; meramente móvel é insuficiente.

Isso pode ser considerado um defeito no C ++ 11, mas você precisaria de alguma syntax para dizer explicitamente que você queria mover o valor unique_ptr para o lambda. A especificação C ++ 11 é cuidadosamente redigida para evitar movimentos implícitos em variables ​​nomeadas; é por isso que o std::move existe e isso é bom .

Para fazer o que você quer, será necessário usar std::bind (que seria semi-complicado, exigindo uma pequena seqüência de binds ) ou apenas retornar um object antigo regular.

Além disso, nunca pegue unique_ptr by && , a menos que você esteja realmente escrevendo seu construtor de movimento. Apenas pegue por valor; a única maneira que um usuário pode fornecer por valor é com std::move . Na verdade, geralmente é uma boa ideia nunca aceitar nada do && , a menos que você esteja escrevendo o operador de construção / atribuição de movimento (ou implementando uma function de encaminhamento).

A solução “semi-complicada” usando std::bind como mencionado por Nicol Bolas não é tão ruim assim:

 std::function getAction(std::unique_ptr&& psomething) { return std::bind([] (std::unique_ptr& p) { p->do_some_thing(); }, std::move(psomething)); } 

Uma solução sub-ótima que funcionou para mim foi converter o unique_ptr em shared_ptr e capturar o shared_ptr no lambda.

 std::function getAction(std::unique_ptr psomething) { //The caller given ownership of psomething std::shared_ptr psomethingShared = std::shared_ptr(std::move(psomething)); return [psomethingShared]() { psomethingShared->do_some_thing(); }; } 

Eu usei essa solução realmente desonesta, que envolve colocar o unique_ptr dentro de um shared_ptr . Isso ocorre porque meu código requeria um unique_ptr (devido a uma restrição de API), portanto, eu não poderia convertê-lo para um shared_ptr (senão nunca conseguiria recuperar meu unique_ptr ).

Minha justificativa para usar essa abominação é que era para o meu código de teste, e eu tinha que std::bind um unique_ptr na chamada de function de teste.

 // Put unique_ptr inside a shared_ptr auto sh = std::make_shared>(std::move(unique)); std::function fnTest = std::bind([this, sh, input, output]() { // Move unique_ptr back out of shared_ptr auto unique = std::move(*sh.get()); // Make sure unique_ptr is still valid assert(unique); // Move unique_ptr over to final function while calling it this->run_test(std::move(unique), input, output); }); 

Agora, chamar fnTest() chamará run_test() passando o unique_ptr para ele. Chamar fnTest() uma segunda vez resultará em uma falha de declaração, porque o unique_ptr já foi movido / perdido durante a primeira chamada.