2016-12-31 128 views
1


我正在使用VC++編譯我的程序(使用Visual Studio 2015,更新3),並且某些代碼段無法編譯。std :: bind無法與std :: atomic_bool和MSVC編譯

基本上,我想綁定一個函數,該函數獲取對原子布爾值的引用與原子布爾值。自包含的代碼:

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類型不是CopyConstructible。您(錯誤)調用std::bind()將創建副本。

此外,您似乎誤解了引用是如何工作的 - auto& ref = b當然會創建對b的引用;但ref本身仍然是一個左值,因此將它傳遞給std::bind()並不會突然改變行爲。

最後,考慮到你正在使用原子能,這是C++ 11,這意味着你還可以使用lambda表達式,這將允許你表達你的代碼,而不必訴諸std::ref

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

但是要小心!在這兩種情況下,無論你使用std::bind + std::ref或我的拉姆達上面的例子,你必須確保b仍然有效,直到你與delegate完成 - 以參考擴展原始對象的生命週期。

相關問題