0

我正在使用 TR1std::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::_Bind<_Result_type,_Ret,_BindN>' 1> with 1>
[ 1> _Result_type=void, 1> _Ret=void, 1>
_BindN=std::tr1::_Bind2,Foo *,std::tr1::_Ph<1>> 1> ] 1> 没有构造函数可以采用源类型,或者构造函数重载决议不明确

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

4

3 回答 3

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_tstd::tr1::_Bind不能std::nullptr_t在三元运算符的上下文中转换为或相反。

if/else另一方面,根本不返回任何东西。

于 2012-10-11T13:41:28.337 回答
0

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

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

从而解决 registerHandler 的多态性以匹配采用绑定结果兼容参数的多态性。

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

于 2012-10-11T13:41:45.933 回答
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.
}
于 2014-04-16T15:52:15.010 回答