2016-06-08 5 views
5

У меня есть следующий фрагмент кода:Почему компилятор не видит метод базового класса при использовании 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 и лязг отвергают этот код, они не могут найти метод Read(int x)

Однако если я раскомментирую using Iface::Read в Crtp, мой код успешно компилируется.

Обратите внимание, что если я возьму ссылку на Iface я могу назвать Read(int x)

Почему это происходит?

ответ

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:

... поиск имени рассматривает областей, как описано ниже, до тех пор, пока не найдет по крайней мере одно объявление любого рода, в это время поиска останавливается и не рассматриваются никакие другие прицелы.

 Смежные вопросы

  • Нет связанных вопросов^_^