为什么三元运算符与if-else在这里不一样?

时间:2012-10-11 13:36:11

标签: c++ visual-studio-2010 c++11 std-function nullptr

我正在使用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>没有构造函数可以采用源类型,或者构造函数重载解析是不明确的

这是编译器的限制,还是我做了一些愚蠢的事情?我知道在这种特殊情况下,使用三元运算符可能无法获得任何好处,但我只是好奇。

3 个答案:

答案 0 :(得分:7)

三元运算符的两个分支必须返回相同类型的值,或者一个值的类型必须可以转换为另一个。

  

5.16.3 ...如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv限定的)类类型,则尝试将每个操作数转换为另一个操作数的类型... [详细说明]使用此过程,确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者一个可以转换,但转换不明确,则程序格式不正确。如果只能进行一次转换,则将该转换应用于所选操作数,并使用转换后的操作数代替本节其余部分的原始操作数。

这就是编译器错误显示...no conversion from 'nullptr' to 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' 1>...

的原因

nullptr的类型为std::nullptr_tstd::function<>有一个接受std::nullptr_t的构造函数。 {3}}无法在三元运算符的上下文中转换为std::tr1::_Bind或相反。

另一方面,

std::nullptr_t根本不会返回任何内容。

答案 1 :(得分:0)

这里我假设registerHandler有多态声明。

我的猜测是,当遇到三元运算符时,编译器将假设以下两部分都是相同的类型。

因此解析registerHandler的多态性以匹配带有绑定结果兼容参数的多态性。

使用if,每个registerHandler调用都是单独解析的,因此根据每个传递的参数类型正确选择好的registerHandler。

答案 2 :(得分:0)

Maxim Yegorushkin的回答是正确的。这是一个简单的解决方法,其示例代码可以更好地说明您的问题:

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.
}