Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这里的三元运算符与if-else不同?_C++_Visual Studio 2010_C++11_Std Function_Nullptr - Fatal编程技术网

C++ 为什么这里的三元运算符与if-else不同?

C++ 为什么这里的三元运算符与if-else不同?,c++,visual-studio-2010,c++11,std-function,nullptr,C++,Visual Studio 2010,C++11,Std Function,Nullptr,我正在使用TR1的std::函数实现一个简单的回调机制。如果我不想被回调,我将nullptr注册为回调处理程序。这将编译并运行良好: void Foo::MessageHandlingEnabled( bool enable ){ if( enable ) m_Bar.RegisterMessageHandler( std::bind(&Foo::BarMessageHandler, this, std::placeholders::_1) ); else

我正在使用TR1的std::函数实现一个简单的回调机制。如果我不想被回调,我将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'1>与1> [1>结果类型=void,1>返回=void,1> _BindN=std::tr1::u Bind2,Foo *,std::tr1::_Ph>1>]1>没有构造函数可以采用源类型,或者构造函数重载解析不明确


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

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

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

这就是为什么编译器错误显示…没有从'nullptr'转换到'std::tr1::_Bind'1>

nullptr的类型为std::nullptr\u t,std::function的构造函数接受std::nullptr\u t。std::tr1::_Bind不能在三元运算符的上下文中转换为std::nullptr_t或其他方式


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

这里我假设registerHandler有多态声明

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

因此,将registerHandler的多态性解析为匹配接受绑定结果兼容参数的多态性


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

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

由于if不在方法的参数列表中,并且不能,因此从语法上讲,这里对if块的“返回值”的任何提及都是误导性的。让我困惑的是,如果您可以在调用RegisterMessageHandler时传递nullptr,它需要std::functionYes,那么它就是一个虚拟方法。但根据另一个答案,同样的情况也会发生在非虚拟方法上。我必须对它进行测试,但我非常确定寄存器函数是否为虚拟函数与此无关。这里的情况不是虚拟性而是多态性。IE:相同的方法名称,不同的参数类型。我通常称之为重载,但很好,有些人认为它是多态性的一种形式。在我的例子中,也没有重载。我的猜测是:该类同时声明了registerHandlersomeType a和registerHandlersomeOtherType b,其中a不能转换为b。使用三元时,SomeType位于:的左侧,someOtherType位于:,唯一解析的符号是调用的registerHandlersomeType