0

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::_Bind<_Result_type,_Ret,_BindN>' 1> への変換がありません 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 ... 2番目と3番目のオペランドの型が異なり、どちらかが(おそらくcv修飾された)クラス型である場合、これらの各オペランドを他の型に変換しようとします...[詳細は省略]このプロセスを使用して、第2オペランドを第3オペランドに一致するように変換できるかどうか、および第3オペランドを第2オペランドに一致するように変換できるかどうかを判別します。両方を変換できる場合、または一方を変換できるが変換があいまいな場合、プログラムの形式が正しくありません。正確に1つの変換が可能な場合、その変換は選択されたオペランドに適用され、このセクションの残りの部分では、変換されたオペランドが元のオペランドの代わりに使用されます。

これがコンパイラエラーが言う理由です...no conversion from 'nullptr' to 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' 1>...

nullptrの型がstd::nullptr_tありstd::function<>、を受け入れるコンストラクターがありますstd::nullptr_t。三項演算子のコンテキストでは、変換またはその逆std::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

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.
}
于 2014-04-16T15:52:15.010 に答える