Ошибка при приведении NULL / nullptr к std :: function & lt; & gt; & amp;

Этот код не встраивается в 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 &'

Это звучит правильно? Я все еще что-то упускаю?

2

Решение

Особое здесь имеет отношение к шаблонным ограничениям конструктора и другим неявным преобразованиям.

Причина по которой 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, компилирующий это, вероятно, ошибка разрешения перегрузки компилятора.

2

Другие решения

Кастинг T к U& никогда не работает, и это намеренно. Вы можете привести к U const&, Причина в том, что изменения во временном объекте U не распространятся обратно на значение T.

VS2010 немного глючит в этом отношении и разрешил приведение (но с правильными настройками, предупредит об этом)

0

По вопросам рекламы [email protected]