为什么编译器在使用CRTP时看不到基类的方法

时间:2016-06-08 08:06:24

标签: c++ inheritance crtp

我有以下代码:

struct Iface
{
    virtual int Read() = 0;

    int Read(int x) {
        return Read() + x;
    }
};

template <typename Impl>
struct Crtp : public Iface
{
    virtual int Read() {
        return static_cast<Impl&>(*this).ReadImpl();
    }
    //using Iface::Read;
};

struct IfaceImpl : public Crtp<IfaceImpl>
{
    int ReadImpl() {
        return 42;
    }
};

int main()
{
    IfaceImpl impl;
    impl.Read(24); // compilation error

    Iface& iface = impl;
    iface.Read(24); // always compiles successfully
}

msvc,gcc和clang都拒绝此代码,他们找不到方法Read(int x)

但是,如果我在using Iface::Read中取消注释Crtp,我的代码就会成功编译。

请注意,如果我参考Iface,我可以致电Read(int x)

为什么会这样?

1 个答案:

答案 0 :(得分:7)

  

为什么会这样?

您的问题与CRTP无关。这是在正常继承方案中可能发生的名称隐藏问题。

当您致电impl.Read(24);时,在Read的班级范围内找不到成员函数名IfaceImpl。然后将检查基类Crtp的范围,并在那里找到名称Read。然后名称查找停止,因此进一步的基类int Read(int x)中的Iface将不会被考虑用于重载解析,即使它在这里更合适。

通过using Iface::Read;,您将名称Read引入Crtp的班级范围。然后可以通过正确的重载分辨率找到并选择它。

如果你通过Iface引用来调用它,名称查找将会很好用。

或者您可以impl.Iface::Read(24);明确地(并且丑陋地)调用它。

请参阅Unqualified name lookup

  

...名称查找检查范围如下所述,直到它找到至少一个任何类型的声明,此时查找停止,不再检查其他范围。