I'm using TR1's std::function
to implement a simple callback mechanism. If I don't want to get called back, I register nullptr
as the callback handler. This compiles and works fine:
void Foo::MessageHandlingEnabled( bool enable ){
if( enable )
m_Bar.RegisterMessageHandler( std::bind(&Foo::BarMessageHandler, this, std::placeholders::_1) );
else
m_Bar.RegisterMessageHandler( nullptr );
}
If I rewrite this using the ternary operator...
void Foo::MessageHandlingEnabled( bool enable ){
m_Bar.RegisterMessageHandler( enable?
std::bind(&Foo::BarMessageHandler, this, std::placeholders::_1) :
nullptr );
}
... VC++'s compiler says:
error C2446: ':' : no conversion from 'nullptr' to '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> No constructor could take the source type, or constructor overload resolution was ambiguous
Is this a limitation of the compiler, or am I doing something stupid? I know I might not gain any benefit, in this particular case, from using the ternary operator, but I'm just curious.
Both branches of the ternary operator must return values of the same type, or the type of one value must be convertible to the other.
5.16.3 ... if the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other... [details omitted] Using this process, it is determined whether the second operand can be converted to match the third operand, and whether the third operand can be converted to match the second operand. If both can be converted, or one can be converted but the conversion is ambiguous, the program is ill-formed. If exactly one conversion is possible, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this section.
This is why the compiler error says ...no conversion from 'nullptr' to 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' 1>...
nullptr
has the type of std::nullptr_t
and std::function<>
has a constructor that accepts std::nullptr_t
. std::tr1::_Bind
can't be converted to std::nullptr_t
or the other way around in the context of the ternary operator.
if/else
on the other hand, doesn't return anything at all.