2013-11-28 1 views
8

기능 :바인딩 기능을 수 std :: 나는 다음과 같은 코드가 작동하게하기 위해 노력하고있어 <void()>

#include <cstdio> 
#include <functional> 
#include <string> 
#include <memory> 

using namespace std; 

class Foo { 
public: 
    Foo(): m_str("foo") { } 

    void f1(string s1, string s2, unique_ptr<Foo> p) 
     { 
      printf("1: %s %s %s\n", s1.c_str(), s2.c_str(), p->str()); 
     } 

    void f2(string s1, string s2, Foo* p) 
     { 
      printf("2: %s %s %s\n", s1.c_str(), s2.c_str(), p->str()); 
     } 

    const char* str() const { return m_str.c_str(); } 

private: 
    string m_str; 
}; 

int main() 
{ 
    string arg1 = "arg1"; 
    string arg2 = "arg2"; 
    Foo s; 
    unique_ptr<Foo> ptr(new Foo); 


    //function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); 
    function<void()> f(bind(&Foo::f2, &s, arg1, arg2, ptr.release())); 

    f(); 
} 

호출 F() 푸에 바인딩을 :: F2는 (마지막 매개 변수는 원시 포인터) 잘 작동하지만 Foo :: f1에 바인딩하면 컴파일 오류가 발생합니다.

test.cpp: In function ‘int main()’: 
test.cpp:36:70: error: no matching function for call to ‘std::function<void()>::function(std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type)’ 
    function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); 
                    ^
test.cpp:36:70: note: candidates are: 
In file included from test.cpp:2:0: 
/usr/include/c++/4.8.2/functional:2251:2: note: template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) 
    function(_Functor); 
^
/usr/include/c++/4.8.2/functional:2251:2: note: template argument deduction/substitution failed: 
/usr/include/c++/4.8.2/functional:2226:7: note: std::function<_Res(_ArgTypes ...)>::function(std::function<_Res(_ArgTypes ...)>&&) [with _Res = void; _ArgTypes = {}] 
     function(function&& __x) : _Function_base() 
    ^
/usr/include/c++/4.8.2/functional:2226:7: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘std::function<void()>&&’ 
/usr/include/c++/4.8.2/functional:2429:5: note: std::function<_Res(_ArgTypes ...)>::function(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {}] 
    function<_Res(_ArgTypes...)>:: 
    ^
/usr/include/c++/4.8.2/functional:2429:5: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘const std::function<void()>&’ 
/usr/include/c++/4.8.2/functional:2206:7: note: std::function<_Res(_ArgTypes ...)>::function(std::nullptr_t) [with _Res = void; _ArgTypes = {}; std::nullptr_t = std::nullptr_t] 
     function(nullptr_t) noexcept 
    ^
/usr/include/c++/4.8.2/functional:2206:7: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘std::nullptr_t’ 
/usr/include/c++/4.8.2/functional:2199:7: note: std::function<_Res(_ArgTypes ...)>::function() [with _Res = void; _ArgTypes = {}] 
     function() noexcept 
    ^
/usr/include/c++/4.8.2/functional:2199:7: note: candidate expects 0 arguments, 1 provided 

무엇이 잘못 되었나요?

gcc 4.8.2 및 -std = C++ 0x (-std = C++ 11 역시 실패 함) 플래그를 사용하고 있습니다.

감사

+1

std :: bind에 rvalues를 전달하는 데 문제가 있습니다. http://stackoverflow.com/questions/4871273/passing-rvalues-through-stdbind를 참조하십시오. f1이 포인터의 소유권을 실제로 획득해야합니까? f1은 const ref를 통해 포인터를 취할 수 있고 std :: ref를 사용하여 std :: bind에 포인터를 전달할 수 있습니다. http://coliru.stacked-crooked.com/a/5ebe39ccca544bea – countfromzero

+1

참조 http://stackoverflow.com/ 질문/9955714/do-stdbind-work-with-move-only-types-in-general-and-stdunique-ptr-in-part – zch

+0

@justinls 그래, 소유권을 가져야하지만, 예를 들어 주셔서 감사합니다. std :: move를 사용하여 작동하게하는 방법을 찾지 못하면 제안을 사용하여 해결 방법을 제안합니다. – rogerzanoni

답변

3

은 흠 정말 r 값 참조를 처리 할 때 그 표준 : : 바인딩이 문제를 가지고 보인다. 하나 개의 대안은 람다 함수를 사용하는 것이다 :

이 그것이 r 값의 기준으로서 unique_ptr 받아들이는 또한 예 F1의 서명을 변경할 필요가 작동하기 위해서는
function<void()> f([&]() { s.f1(arg1,arg2,std::move(ptr)); }); 

:

void f1(string s1, string s2, unique_ptr<Foo>&& p) 

(std :: bind가 r 값 참조를 처리 할 수있는 경우에도 std :: unique_ptr에 복사 생성자가 없으므로 이동 생성자 만 액세스 할 수 있기 때문에 여전히이 작업을 수행해야합니다.)

참고 그러나 당신의 생성은 다소 위험합니다 (std :: bind가 작동한다면) : i f()를 두 번 호출하면 런타임 예외가 발생합니다.

+0

C++ 11에서는 이와 같이 람다 식에서'unique_ptr'을 쉽게 포착 할 수 없다는 것에 유의하십시오. 이 메소드를 호출하면 원래의 'unique_ptr'이 범위를 벗어나면 함수를 호출하면 런타임에 널 포인터 예외가 발생합니다. 몇 가지 해결 방법은 [이 질문] (http://stackoverflow.com/questions/8236521/how-to-capture-a-unique-ptr-into-a-lambda-expression)을 참조하십시오. – Malvineous

8

다른 답변 (이 글을 쓰는 시점)에서 설명한 바인드 문제는 컴파일러가 질문에서 불평하지 않는 내용입니다. 문제는 std::function이 CopyConstructible이어야하며 인수 (함수에 의해 저장 됨)가 CopyConstructible이어야한다는 것입니다. 표준 [20.9.11.2 클래스 템플릿 기능]에서

template<class F> function(F f); 
template <class F, class A> function(allocator_arg_t, const A& a, F f); 

Requires: F shall be CopyConstructible. f shall be Callable (20.9.11.2) for argument types ArgTypes and return type R . The copy constructor and destructor of A shall not throw exceptions...

조차의 결합을 포함하지 않는 예 고려해 여기

#include <functional> 
#include <memory> 

using namespace std; 

struct NonCopyableFunctor { 
    NonCopyableFunctor(){} 
    NonCopyableFunctor(const NonCopyableFunctor &) = delete; 
    NonCopyableFunctor(NonCopyableFunctor &&){} 
    void operator()(){} 
}; 

int main() 
{ 
    NonCopyableFunctor fun; 
    function<void()> vfun(move(fun)); // even though I move here, 
    // it still complains about a copy going on elsewhere. 
} 

는 그 소리의 출력의 :

[[email protected] ~]$ clang++ -std=c++11 bound_unique.cc 
In file included from bound_unique.cc:1: 
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:1911:10: error: call to deleted constructor of 'NonCopyableFunctor' 
      new _Functor(*__source._M_access<_Functor*>()); 
       ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:1946:8: note: in instantiation of member function 
     'std::_Function_base::_Base_manager<NonCopyableFunctor>::_M_clone' requested here 
       _M_clone(__dest, __source, _Local_storage()); 
      ^
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:2453:33: note: in instantiation of member function 
     'std::_Function_base::_Base_manager<NonCopyableFunctor>::_M_manager' requested here 
      _M_manager = &_My_handler::_M_manager; 
            ^
bound_unique.cc:16:20: note: in instantiation of function template specialization 'std::function<void()>::function<NonCopyableFunctor, void>' requested here 
    function<void()> vfun(move(fun)); 
       ^
bound_unique.cc:8:3: note: function has been explicitly marked deleted here 
    NonCopyableFunctor(const NonCopyableFunctor &) = delete; 
^
1 error generated. 

unique_ptr을 바인드하면 결과 바인드 오브젝트는 복사 할 수 없게됩니다. 어쨌든 바인딩은 여전히 ​​컴파일됩니다. function가 호출 객체를 필요로하기 때문에 다음 코드는

function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); 
// just define f, not even call it 

를 컴파일되지 않습니다

1

1) 복사 작도하지만 bindunique_ptr 같은 비 복사 가능한 인수를 취하는 경우 반환 펑이 아닌 복사 가능한 것, 다른 답변에서 언급했듯이

2) bindfunction을 사용하지 마십시오.그러나 다음 코드 때문에 단계 중 하나

auto f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); // a 
f();             // b 

를 컴파일되지 않습니다 (가)는 (reference_wrapper 제외) 좌변로에주고, 단계에서 내부 펑에 전달 무엇 bind 저장 (B) . 따라서 바운드 인수는 참조가 아닌 값으로 전달되는 매개 변수에 대해 복사 가능해야합니다.

3) 그런 다음 원시 포인터를 사용해보십시오. 그러나 다음 코드는 컴파일되지 않습니다 중 하나

auto f(bind(&Foo::f1, &s, arg1, arg2, ptr.release())); 
f(); 

(2) 펑터가 int*을 저장하고 호출 할 때 매개 변수 유형 unique_ptr<int>로 변환하려고 같은 유사한 이유. 그러나 생성자 unique_ptr(pointer p)explicit입니다.

는 는

그것을 컴파일하려면 , 당신은 f 여러 번 호출 할 수 있음이

void f3(string s1, string s2, unique_ptr<Foo>& p) 
//           ^use reference; add const if you need 
{ 
    printf("3: %s %s %s\n", s1.c_str(), s2.c_str(), p->str()); 
} 

auto f(bind(&Foo::f3, &s, arg1, arg2, std::move(ptr))); 
f(); 

참고하고, 매개 변수 bind의 반환 된 객체에 저장되어 p 참조 같은 unique_ptr 같은 기능이 필요


.

관련 문제