我正在使用TR1的std::function
来实现一个简单的回调机制。如果我不想回调,我将nullptr
注册为回调处理程序。这编译并正常工作:
void Foo::MessageHandlingEnabled( bool enable ){
if( enable )
m_Bar.RegisterMessageHandler( std::bind(&Foo::BarMessageHandler, this, std::placeholders::_1) );
else
m_Bar.RegisterMessageHandler( nullptr );
}
如果我使用三元运算符重写它......
void Foo::MessageHandlingEnabled( bool enable ){
m_Bar.RegisterMessageHandler( enable?
std::bind(&Foo::BarMessageHandler, this, std::placeholders::_1) :
nullptr );
}
... VC ++的编译器说:
错误C2446:':':没有从'nullptr'转换为 '的std :: TR1 :: _绑定< _Result_type,_ret,_BindN>' 1 GT; 1 >> [1> _Result_type = void,1> _Ret = void,1>
_BindN =标准:: TR1 :: _ Bind2,富 *,性病:: TR1 :: _ pH值小于1为卤素;> 1 GT; ] 1>没有构造函数可以采用源类型,或者构造函数重载解析是不明确的
这是编译器的限制,还是我做了一些愚蠢的事情?我知道在这种特殊情况下,使用三元运算符可能无法获得任何好处,但我只是好奇。
答案 0 :(得分:7)
三元运算符的两个分支必须返回相同类型的值,或者一个值的类型必须可以转换为另一个。
5.16.3 ...如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv限定的)类类型,则尝试将每个操作数转换为另一个操作数的类型... [详细说明]使用此过程,确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者一个可以转换,但转换不明确,则程序格式不正确。如果只能进行一次转换,则将该转换应用于所选操作数,并使用转换后的操作数代替本节其余部分的原始操作数。
这就是编译器错误显示...no conversion from 'nullptr' to 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' 1>...
nullptr
的类型为std::nullptr_t
,std::function<>
有一个接受std::nullptr_t
的构造函数。 {3}}无法在三元运算符的上下文中转换为std::tr1::_Bind
或相反。
std::nullptr_t
根本不会返回任何内容。
答案 1 :(得分:0)
这里我假设registerHandler有多态声明。
我的猜测是,当遇到三元运算符时,编译器将假设以下两部分都是相同的类型。
因此解析registerHandler的多态性以匹配带有绑定结果兼容参数的多态性。
使用if,每个registerHandler调用都是单独解析的,因此根据每个传递的参数类型正确选择好的registerHandler。
答案 2 :(得分:0)
struct Base{};
struct DerivedA:public Base{};
struct DerivedB:public Base{};
DerivedA a;
DerivedB b;
doesNotWork()
{
bool chooseA = true;
Base& base = chooseA?a:b; // Error: compiler tries to convert b to DerivedA (the type of a).
}
Base& choose(bool x)
{
if(x) return a;
return b;
}
works()
{
bool chooseA = true;
Base& base = choose(chooseA); //Helper function converts a or b to parent class Base.
}