2015-08-06 14 views
6

Próbuję użyć funkcji przechwytywania init C++ 14, aby przenieść unikalny_ptr wewnątrz lambda poprzez przechwytywanie. Z jakiegoś powodu zarówno gcc, jak i clang nie chcą skompilować mojego kodu, twierdząc, że próbuję skopiować unique_ptr, co oczywiście nie działa. Pomyślałem, że unikanie kopii było właśnie celem funkcji init-capture + std::move - w rzeczywistości podanie unique_ptr wydaje się być najlepszym przykładem używanym przez wszystkich.Dlaczego funkcja init-capture lambda nie działa dla unique_ptr?

Co robię źle?

#include <functional> 
#include <iostream> 
#include <memory> 
#include <string> 

void runFunc(std::function<void()>&& f) { 
    auto ff = std::move(f); 
    ff(); 
} 

int main() { 
    auto ptr = std::make_unique<std::string>("hello world\n"); 
    runFunc([captured_ptr = std::move(ptr)]() { 
     std::cout << *captured_ptr; 
    }); 
} 

Wyjście z gcc:

http://coliru.stacked-crooked.com/a/d91a480b2b6428ac

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out 
In file included from main.cpp:1:0: 
/usr/local/include/c++/5.2.0/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 = main()::<lambda()>; std::false_type = std::integral_constant<bool, false>]': 
/usr/local/include/c++/5.2.0/functional:1746:16: required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = main()::<lambda()>]' 
/usr/local/include/c++/5.2.0/functional:2260:19: required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = main()::<lambda()>; <template-parameter-2-2> = void; _Res = void; _ArgTypes = {}]' 
main.cpp:15:6: required from here 
/usr/local/include/c++/5.2.0/functional:1710:34: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 
    __dest._M_access<_Functor*>() = 
           ^
main.cpp:13:43: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed: 
    runFunc([captured_ptr = std::move(ptr)]() { 
             ^
main.cpp:13:43: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = std::__cxx11::basic_string<char>; _Dp = std::default_delete<std::__cxx11::basic_string<char> >]' 
In file included from /usr/local/include/c++/5.2.0/memory:81:0, 
       from main.cpp:3: 
/usr/local/include/c++/5.2.0/bits/unique_ptr.h:356:7: note: declared here 
     unique_ptr(const unique_ptr&) = delete; 

Wyjście z brzękiem:

http://coliru.stacked-crooked.com/a/4374988d875fcedc

In file included from main.cpp:1: 
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1711:10: error: call to implicitly-deleted copy constructor of '(lambda at main.cpp:13:13)' 
      new _Functor(*__source._M_access<_Functor*>()); 
       ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1746:8: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at main.cpp:13:13)>::_M_clone' requested here 
       _M_clone(__dest, __source, _Local_storage()); 
      ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:2260:33: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at main.cpp:13:13)>::_M_manager' requested here 
      _M_manager = &_My_handler::_M_manager; 
            ^
main.cpp:13:13: note: in instantiation of function template specialization 'std::function<void()>::function<(lambda at main.cpp:13:13), void>' requested here 
    runFunc([captured_ptr = std::move(ptr)]() { 
      ^
main.cpp:13:14: note: copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor 
    runFunc([captured_ptr = std::move(ptr)]() { 
      ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/unique_ptr.h:356:7: note: 'unique_ptr' has been explicitly marked deleted here 
     unique_ptr(const unique_ptr&) = delete; 
    ^
1 error generated. 

Odpowiedz

10

Ponieważ std::function musi być copyable:

std::function spełnia wymogi CopyConstructible i CopyAssignable.

A constructor w pytaniu:

Inicjuje celz kopii z f.

Konstrukcja lambda (całkowicie ważna) ma element unique_ptr, co powoduje, że nie można jej kopiować. Jeśli przepisał runFunc wziąć dowolny funktor o wartości:

template <typename F> 
void runFunc(F f) { 
    auto ff = std::move(f); 
    ff(); 
} 

byłoby skompilować.

+0

Świetne wyjaśnienie problemu, ale rozwiązanie jest bardzo ograniczone. Co jeśli chcę zapisać gdzieś "wskaźnik funkcji"? Czy istnieje typ inny niż 'std :: function', który może być użyty? – ugoren

Powiązane problemy