2016-12-31 23 views
1


VC++을 사용하여 프로그램을 컴파일하고 (Visual Studio 2015, 업데이트 3 사용) 일부 스 니펫은 컴파일되지 않습니다.std :: bind는 MSVC에서 std :: atomic_bool &로 컴파일하지 못했습니다.

기본적으로 원자 부울로 참조를 가져 오는 함수를 바인드하고 싶습니다. 자기 포함 된 코드 :

void stub(std::atomic_bool& b) { 
    b = true; 
} 

int main() { 
    std::atomic_bool b(false); 
    std::function<void()> delegate = std::bind(stub, b); //fails to compile 

    auto& ref = b; 
    std::function<void()> delegate0 = std::bind(stub, ref); //fails to compile 

    std::function<void()> delegate1 = std::bind(stub, std::ref(b)); //compiled 
/*...*/ 
    } 

컴파일러 스택 추적 :

1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility(357): error C2665: 'std::tuple<std::atomic<bool>>::tuple': none of the 2 overloads could convert all the argument types 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\tuple(608): note: could be 'std::tuple<std::atomic<bool>>::tuple(std::tuple<std::atomic<bool>> &&)' 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\tuple(607): note: or  'std::tuple<std::atomic<bool>>::tuple(const std::tuple<std::atomic<bool>> &)' 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility(357): note: while trying to match the argument list '(std::atomic<bool>)' 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(866): note: see reference to function template instantiation 'std::_Compressed_pair<void (__cdecl *)(std::atomic_bool &),std::tuple<std::atomic<bool>>,false>::_Compressed_pair<void(__cdecl &)(std::atomic_bool &),_Cv_TiD&>(std::_One_then_variadic_args_t,_Other1,_Cv_TiD &)' being compiled 
1>   with 
1>   [ 
1>    _Cv_TiD=std::atomic<bool>, 
1>    _Other1=void (__cdecl &)(std::atomic_bool &) 
1>   ] 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(864): note: see reference to function template instantiation 'std::_Compressed_pair<void (__cdecl *)(std::atomic_bool &),std::tuple<std::atomic<bool>>,false>::_Compressed_pair<void(__cdecl &)(std::atomic_bool &),_Cv_TiD&>(std::_One_then_variadic_args_t,_Other1,_Cv_TiD &)' being compiled 
1>   with 
1>   [ 
1>    _Cv_TiD=std::atomic<bool>, 
1>    _Other1=void (__cdecl &)(std::atomic_bool &) 
1>   ] 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(863): note: while compiling class template member function 'std::_Binder<std::_Unforced,void (__cdecl &)(std::atomic_bool &),std::atomic_bool &>::_Binder(_Fx,std::atomic_bool &)' 
1>   with 
1>   [ 
1>    _Fx=void (__cdecl &)(std::atomic_bool &) 
1>   ] 
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(890): note: see reference to function template instantiation 'std::_Binder<std::_Unforced,void (__cdecl &)(std::atomic_bool &),std::atomic_bool &>::_Binder(_Fx,std::atomic_bool &)' being compiled 
1>   with 
1>   [ 
1>    _Fx=void (__cdecl &)(std::atomic_bool &) 
1>   ] 
1> c:\visual studio 2015\projects\quantum\quantum\main.cpp(658): note: see reference to class template instantiation 'std::_Binder<std::_Unforced,void (__cdecl &)(std::atomic_bool &),std::atomic_bool &>' being compiled 

뭔가 내가 그리워하거나 컴파일러 잘못이 있습니까?

+3

원자는 복사 할 수 없습니다. 그래서'std :: ref'가 필요합니다. –

+0

@KerrekSB 왜 프로그램이 원자를 복사하려고합니까? 이 함수는 매개 변수로 참조를 가져오고, 원자는 참조로 전달되며, 참조 옆에 복사되는 내용을 볼 수 없습니다. –

+0

C++ 유형 및 객체 모델에 대한 근본적인 오해가있는 것으로 보입니다. 당신은 절대로 "참조를 복사하십시오". 항상 * 값을 복사합니다. 값은 절대 참조가 아닙니다. 참조는 값을 지정하는 데 사용할 수있는 일종의 변수 *입니다. 그래서 여러분이'ref'라고 말할 때, 그것은'std :: atomic_bool' 타입의 값입니다 (그리고 그것은'b'와 같은 값이됩니다). 'std :: ref (b)'(또는'std :: ref (ref)')를 말할 때 그것은'std :: reference_wrapper '형의 값이고'std :: bind' 그것을 해석하기위한 프로토콜이 있습니다. –

답변

2

bind은 항상 을 참조하려고합니다. atomic 유형을 복사 할 수 없습니다. 따라서 bind이 복사를 시도하면 실패합니다.

이것은 값이 예상되는 곳에서 개체에 대한 참조를 허용하는 이유 중 하나입니다. reference_wrapper이 존재하는 이유 중 하나입니다. 사실 std::ref은 주로 bind을 처리하기 위해 개발되었습니다.

참조 : bind에는 매개 변수에 대한 참조가 저장 될 수 있습니다. 그러나 참조를 저장하는 것은 매우 위험 할 수 있습니다. 특히 스택 변수에 대한 참조는 bind 펑터가 호출되기 전에 기존의 것을 멈출 수 있습니다. 따라서 bind은 참조를 저장할 때 약 이되도록 명시 적으로이됩니다. 그것은 ref을 사용하게합니다.

+0

@DavidHaim : 참조가 객체가 아닙니다. 'bind'는 항상 값을 저장합니다; 복사 또는 이동 여부는 함수에 전달한 내용에 따라 다릅니다. 그러나 참조가 아닌 값을 저장합니다. –

+0

@ Nicole Bolas, 나는 당신의 논리에 반드시 동의하지 않습니다. C++은 안전하지 않은 언어입니다. 함수에서 지역 변수에 대한 포인터 나 참조를 반환 할 수 있습니다. 바인딩 된 표현식 안에 매달려있는 포인터를 저장할 수 있습니다. 해당 비용에 대한 참조 해제는 의미가 없습니다. –

+0

@DavidHaim : "* 나는 당신의 논리에 반드시 동의하지 않는다. *"당신이 원하는 모든 것에 동의하거나 동의하지 않는다. 그러나 그것이 Boost (그리고 표준 라이브러리 버전)가 이런 식으로했던 이유이다. 나는 그 문제에 대한 그들의 입장을 말하고있다. 언어가 안전하지 않다고해서 더 안전하지 않은 것들을 만들어야한다는 의미는 아닙니다. 결국 C++은 그러한 것들을 반환 할 때'&'또는'*'를 사용해야하므로 적어도 잠재적으로 안전하지 않을 때를 알 수 있습니다. 기본적으로 C++은 값을 전달/반환합니다. –

1

std::atomic 유형은 복사 할 수 없습니다. std::bind()에 대한 (오류가있는) 호출은 사본을 작성합니다.

또한 참조가 어떻게 작동하는지 오해하는 것 같습니다. auto& ref = b은 물론 b에 대한 참조를 만듭니다. 그러나 ref은 여전히 ​​자신의 권리 인 lvalue이고 따라서이를 std::bind()으로 전달해도 갑자기 동작이 변경되지 않습니다.

std::function<void()> delegate = [&b] { b = true; }; 

:

마지막으로, C++ 11 아토을 사용하고 고려, 이것은 당신이 또한 당신이 std::ref에 의존하지 않고 코드를 표현할 수 있도록 할 람다에 액세스 할 수있는 의미 그러나주의하십시오! 각각의 경우에, 당신은 std::bind + std::ref를 사용하는지 또는 내 람다 위의 예는, 당신은 당신이 delegate 함께 할 때까지 b이 유효 있는지 확인해야합니다 - 원래 개체의 수명을 연장하지 않는 참조 을 복용.