Этот код не встраивается в VC2013: (РЕДАКТИРОВАТЬ: я не спрашиваю, почему он не встраивается)
#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 ctor (MyStruct( std::function<void()>& func)
дает совсем другую ошибку:
1> F: \ работа \ главной \ DEV \ Common \ teststdfunction \ teststdfunction \ teststdfunction.cpp (16):
ошибка C2664: ‘MyStruct :: MyStruct (const MyStruct &) ‘: не может конвертировать
аргумент 1 от ‘int’ до ‘std :: function &’
Который имеет больше смысла, чем исходная ошибка, и теперь исправление NULL в nullptr не реши это. Почему int (или nullptr) отказывается от приведения к std::function<>&
но согласен отдать const std::function<>&
?
2) Исходный код компилируется и работает как положено в VS2010. Это неясная ошибка библиотеки VS2010?
РЕДАКТИРОВАТЬ:
Что касается вопроса о константном / неконстантном, то теперь я думаю, что задействованное приведение типов и потенциальное несоответствие типов — это, вероятно, красная сельдь. Переданный аргумент — NULL или nullptr — является литералом и, следовательно, const. Он просто не может связываться с неконстантной ссылкой. Например:
const int& a = 8; // Ok
int& b = 9; // error C2440: 'initializing' : cannot convert from 'int' to 'int &'
Это звучит правильно? Я все еще что-то упускаю?
Особое здесь имеет отношение к шаблонным ограничениям конструктора и другим неявным преобразованиям.
Причина по которой nullptr
работает потому что std::function
имеет определенный конструктор, принимающий его. Этот конструктор всегда будет наилучшим совпадением для этого аргумента, потому что шаблоны функций ранжируются как более низкие предпочтения, а все остальные равны.
Обычно, 0
будет неявно преобразовывать в nullptr
и это нормально. Проблема в том, что он может также передается конструктору шаблона функции без ограничений, который конструируется из функциональных объектов. Это не требует неявного преобразования, поэтому все не равны, поэтому этот конструктор предпочтителен, что приводит к ошибке, которую вы видите, что int
не является допустимым функциональным объектом.
libstdc ++ и libc ++ не демонстрируют такое поведение, потому что они реализовали исправление C ++ 14 для этой проблемы, которое ограничивает конструктор. C ++ 11 этого не сделал, поэтому такое поведение вполне соответствует реализации C ++ 11.
Этот вопрос почему NULL
это ужасная вещь, которую вы не должны использовать. На самом деле, команда VS2010 должна была спешить nullptr
из двери в качестве дополнительной функции в последнюю минуту, потому что NULL
так плохо взаимодействует с любой другой функцией в C ++, особенно с C ++ 11.
За const
против неconst
ссылки, другие ответы объяснили эту проблему адекватно.
Есть другие WTF, которые вы можете найти при использовании std::function
без ограниченного конструкторского исправления, поставляемого в C ++ 14 — это не единственный. Короче говоря, это недостаток стандарта C ++ 11, и не в ВС VS2010, компилирующий это, вероятно, ошибка разрешения перегрузки компилятора.
Кастинг T
к U&
никогда не работает, и это намеренно. Вы можете привести к U const&
, Причина в том, что изменения во временном объекте U не распространятся обратно на значение T.
VS2010 немного глючит в этом отношении и разрешил приведение (но с правильными настройками, предупредит об этом)