模板类的模糊多重继承

nya*_*108 11 c++ multiple-inheritance overload-resolution name-lookup template-classes

我有一个真实的情况,可以在下面的例子中总结:

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;
}
Run Code Online (Sandbox Code Playgroud)

为什么编译器不明显B是a TimeListener,因此唯一可能的重载解决方案是Notifier< TimeListener >::add_listener( TimeListener& )

Tar*_*ama 9

成员名称的查找规则表明您的代码不明确,因为该名称位于两个基类中,因此查找集无效.您不需要熟悉查找集和合并的所有细节; 重要的细节是检查两个基类并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
};
Run Code Online (Sandbox Code Playgroud)

Live Demo


Pyr*_*rce 6

标准指示编译器不够智能来解析符号 - 它被定义为一个模糊的操作,尽管你可以在这个实例中逻辑地处理它.在找到两个可能的符号后,您的编译器可能只查找符号名称而不是原型.

您可以通过消除您知道应该接受的模板符号的歧义来告诉编译器您明确接受这两种类型.这将使编译器接受任一表单,然后应用模板.以下是此示例.我目前无法在我的计算机上测试它,但如果编译器在原始示例中难以解析符号,它应该可以工作:

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{
   using Notifier< TimeListener >::add_listener;
   using Notifier< SpaceListener >::add_listener;
};
Run Code Online (Sandbox Code Playgroud)

  • 这不是编译器不够智能,标准说这是不明确的. (6认同)