2014-12-07 20 views
1

此代碼不能建立VC2013:(編輯:我不是問爲什麼不建)故障時鑄造NULL/nullptr到std ::功能<>&

#include <functional> 

struct MyStruct 
{ 
    std::function<void()> m_Func; 
    MyStruct(const std::function<void()>& func) : m_Func(func) {} 
}; 


int main() 
{ 
    MyStruct rc(NULL); 
    return 0; 
} 

出現錯誤:

1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(283): error C2064: term does not evaluate to a function taking 0 arguments 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<int,false>::_ApplyX<_Rx,>(void)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Rx=void 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<int,false>::_ApplyX<_Rx,>(void)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Rx=void 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(226) : while compiling class template member function 'void std::_Func_impl<_MyWrapper,_Alloc,_Ret,>::_Do_call(void)' 
1>   with 
1>   [ 
1>    _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Ret=void 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(495) : see reference to class template instantiation 'std::_Func_impl<_MyWrapper,_Alloc,_Ret,>' being compiled 
1>   with 
1>   [ 
1>    _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Ret=void 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Ty,_Alloc>(_Fty &&,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Fty=int 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Ty,_Alloc>(_Fty &&,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Fty=int 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Ty,std::allocator<std::_Func_class<_Ret,>>>(_Fty &&,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Fty=int 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Ty,std::allocator<std::_Func_class<_Ret,>>>(_Fty &&,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Fty=int 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<_Ty>(_Fty &&)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Fty=int 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<_Ty>(_Fty &&)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Ty=int 
1> ,   _Fty=int 
1>   ] 
1>   f:\work\teststdfunction\teststdfunction.cpp(16) : see reference to function template instantiation 'std::function<void (void)>::function<int>(_Fx &&)' being compiled 
1>   with 
1>   [ 
1>    _Fx=int 
1>   ] 
1>   f:\work\teststdfunction\teststdfunction.cpp(16) : see reference to function template instantiation 'std::function<void (void)>::function<int>(_Fx &&)' being compiled 
1>   with 
1>   [ 
1>    _Fx=int 
1>   ] 

(注意最後兩次報告的錯誤中的'_Fx = int')。

我可以住在那,因爲改變MyStruct rc(NULL)MyStruct rc(nullptr)解決了這個錯誤。但是有兩件事仍是一個謎:

1)去除MYSTRUCT構造函數const屬性(MyStruct(std::function<void()>& func)給出了一個非常,非常不同的錯誤:

1>f:\work\main\dev\common\teststdfunction\teststdfunction\teststdfunction.cpp(16): error C2664: 'MyStruct::MyStruct(const MyStruct &)' : cannot convert argument 1 from 'int' to 'std::function &'

哪個更有意義比原來的錯誤,現在固定NULL到nullptr 解決它。爲什麼INT(或nullptr)拒絕轉換爲std::function<>&但同意轉換爲const std::function<>&

2)原代碼編譯和預期VS2010工作。這是一個晦澀的VS2010庫錯誤?


編輯: 至於常量/非const的問題去,我覺得現在的鑄造參與和潛在的類型不匹配可能是一個紅色的鯡魚。傳遞的參數 - NULL或nullptr - 是一個文字,因此是一個常量。它只是不能綁定到非const引用。例如:

const int& a = 8; // Ok 
int& b = 9; // error C2440: 'initializing' : cannot convert from 'int' to 'int &' 

這聽起來沒錯嗎?我還錯過了什麼嗎?

+1

'nullptr'是'nullptr_t'類型的值,它是'std :: function'的構造函數接受的值。 'NULL'不一定定義爲'nullptr',可能是一個不同的值。使用'nullptr'不要'NULL。 – 2014-12-07 14:24:16

+1

如上所述,我確實改爲nullptr。我不問爲什麼原始代碼沒有編譯。 – 2014-12-07 14:25:46

+1

文字不是一成不變的。他們是rvalues。這是完全不同的事情。不要傳播那個不正確的神話。 – Puppy 2014-12-07 15:06:53

回答

1

在這裏特別有構造模板緊張等隱式轉換做。

nullptr的工作原因是因爲std::function有一個特定的構造函數採取它。這個構造函數將始終是該參數的最佳匹配項,因爲函數模板被排列爲較低的優先級,其他都相同。

通常,0將隱式轉換爲nullptr,這很好。問題是它可以將傳遞給從函數對象構造的無約束函數模板構造函數。這不需要隱式轉換,因此所有不等於,所以此構造函數是首選的 - 這會導致錯誤,您會看到int不是有效的函數對象。

的libstdC++)和libc(++,因爲他們已經實現了C++ 14修復了這個問題,這限制了構造不不出現此行爲。 C++ 11沒有這麼做,這種行爲完全符合C++ 11的實現。

這種問題是爲什麼NULL是一個可怕的事情,你不應該使用。事實上,由於NULL與C++中的所有其他功能(特別是C++ 11)之間的交互非常糟糕,因此VS2010團隊不得不在最後一刻急於將nullptr作爲附加功能。

對於const vs非const參考文獻,其他答案已充分說明問題。

在使用std::function時,如果沒有C++ 14提供的受約束構造函數修復,您可以找到其他的WTF,但這不是唯一的。總而言之,它是VS中的C++ 11標準和而不是的缺陷。編譯它的VS2010可能是一個編譯器重載解析錯誤。

+0

感謝您的回答。我仍然不明白爲什麼SFINAE沒有踢進去。說0與無約束的模板相匹配,但是之後失敗了 - 不應該在接下來的比賽中嘗試nullptr_t專精? – 2014-12-07 21:37:49

+0

@Ofek:SFINAE僅適用於函數簽名。它通常不適用於身體。 – Puppy 2014-12-27 13:15:42

0

T投射到U&從未有效,這是故意的。你可以投到U const&。原因是對臨時U對象的更改不會傳播回T值。

VS2010略微Buggy在這方面,並沒有讓投(但正確的設置,將發出警告吧)

+0

不知道我明白。很明顯,void f(int&i)可以接受一個int類型 - 不符合從T到U& – 2014-12-07 21:29:57

+0

@OfekShilon:不,它不能:'f(4)'被拒絕,儘管'4'是一個明顯的'int'。這就是'T'到'T' - 你也不能改變'4'。 – MSalters 2014-12-07 22:52:33

+0

不是4 a * const * int? AFAIK無法綁定4到一個int&是double:(a)它是const,(b)它是一個右值。 – 2014-12-08 06:07:31