11

次の例に要約できる実際の状況があります。

template< typename ListenerType >
struct Notifier
{
    void add_listener( ListenerType& ){}
};

struct TimeListener{ };
struct SpaceListener{ };

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{

};

struct B : TimeListener{ };

int main()
{
    A a;
    B b;

    a.add_listener( b );    // why is ambiguous?

    return 0;
}

BがであるTimeListenerことをコンパイラが認識できないのはなぜNotifier< TimeListener >::add_listener( TimeListener& )ですか。

4

2 に答える 2

9

メンバー名のルックアップ ルールは、名前が 2 つの基本クラスで検出され、ルックアップ セットが無効であるため、コードがあいまいであると述べています。ルックアップ セットとマージのすべての詳細に精通している必要はありません。重要な詳細は、両方の基本クラスがチェックされ、名前add_listenerが両方で検出されることです。これにより、あいまいさが生じます。

A簡単な解決策は、これらの基本クラス名を using 宣言で取り込むことです。これは、 の両方のバージョンが基本クラスではなく でadd_listener検索されることを意味するため、マージのあいまいさはありません。A

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{
    using Notifier<TimeListener>::add_listener;
    using Notifier<SpaceListener>::add_listener;
   //plus any more base classes
};

Live Demo

于 2016-03-08T17:43:35.067 に答える
6

標準で示されているコンパイラは、シンボルを解決するほどスマートではありません。このインスタンスでは論理的に解決できるという事実にもかかわらず、あいまいな操作として定義されています。コンパイラは、可能な両方のシンボルを見つけた後、おそらくシンボル名のみを探しており、プロトタイプを探していません。

受け入れる必要があることがわかっているテンプレート シンボルのあいまいさを解消することで、両方の型を明示的に受け入れることをコンパイラに伝えることができます。これにより、コンパイラはいずれかの形式を受け入れてから、テンプレートを適用します。以下はその例です。現在、自分のコンピューターでこれをテストすることはできませんが、コンパイラーが元の例のシンボルを解決できない場合は機能するはずです。

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{
   using Notifier< TimeListener >::add_listener;
   using Notifier< SpaceListener >::add_listener;
};
于 2016-03-08T17:41:41.507 に答える