将NULL / nullptr转换为std :: function<>&

时间:2014-12-07 14:22:49

标签: c++ visual-c++-2010 visual-c++-2013

此代码无法在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>          ]

(注意&#39; _Fx = int&#39;在最后两次报告的错误中)。

我可以忍受,因为将MyStruct rc(NULL)更改为MyStruct rc(nullptr)可以解决错误。然而,有两件事仍然是个谜:

1)从MyStruct ctor中移除const限定符(MyStruct( std::function<void()>& func)会产生一个非常非常不同的错误:

  

1&GT; F:\工作\主\ dev的\共同\ teststdfunction \ teststdfunction \ teststdfunction.cpp(16):   错误C2664:&#39; MyStruct :: MyStruct(const MyStruct&amp;)&#39; :无法转换   参数1来自&#39; int&#39;到&#39; std :: function&amp;&#39;

哪个比原始错误更有意义,现在将NULL修复为nullptr 并没有解决它。为什么int(或nullptr)拒绝转换为std::function<>&但同意转换为const std::function<>&

2)原始代码在VS2010中编译并按预期工作。这是一个模糊的VS2010库错误吗?


编辑: 就const / non const问题而言,我现在认为涉及的演员和潜在的类型不匹配可能是一个红色的鲱鱼。传递的参数 - NULL或nullptr - 是一个文字,因此是一个const。它只是无法绑定到非const引用。例如:

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

这听起来不错吗?我还缺少什么吗?

2 个答案:

答案 0 :(得分:2)

这里的特殊内容与构造函数模板约束和其他隐式转换有关。

nullptr之所以有效,是因为std::function有一个特定的构造函数。此构造函数始终是该参数的最佳匹配,因为函数模板被排名为低优先级,其他条件相同。

通常情况下,0会隐式转换为nullptr,这很好。问题是它可以传递给从函数对象构造的无约束函数模板构造函数。这不需要隐式转换,因此所有都不相等,因此首选此构造函数 - 这会导致您看到int不是有效函数对象的错误。

libstdc ++和libc ++不会出现这种行为,因为他们已经针对此问题实现了C ++ 14修复,这会限制构造函数。 C ++ 11没有这样做,这种行为非常符合C ++ 11的实现。

这种问题是为什么NULL是一个你不应该使用的可怕的东西。实际上,VS2010团队在最后一刻不得不急于nullptr作为附加功能,因为NULL与C ++中的所有其他功能交互得非常糟糕,尤其是C ++ 11

对于const与非const引用,其他答案已充分解释了该问题。

使用std::function时,如果没有C ++ 14中提供的约束构造函数修补程序,您可以找到其他WTF-这不是唯一的WTF。长和短是它是C ++ 11标准中的缺陷,而VS中的不是。 VS2010编译它可能是编译器重载解析错误。

答案 1 :(得分:0)

T投射到U&永远不会有效,这是故意的。您可以转换为U const&。原因是对临时U对象的更改不会传播回T值。

VS2010在这方面略显错误,并且确实允许演员阵容(但有适当的设置,会警告它)