2015-02-09 3 views
3

Во время рефакторинга довольно большой базы кода мой компилятор придумал отличный способ понять меня. Это минимальный пример того, что я говорю:C++ tokenizing безумие с шаблонами и виртуальными функциями

#include <iostream> 

class Foo { 
public: 
     virtual int get() = 0; 
     template <typename T> int get(int i) { return 4 + i; } 
}; 

class Bar : public Foo { 
public: 
     virtual int get() { return 3; } 
}; 

int main(int argv, char **argc) { 
     Bar b; 
     std::cout << b.get<char>(7) << std::endl; 
     return 0; 
} 

Clang 3.6, GCC 4.7, GCC 4.8 и GCC 4.9 все разметить на "b.get (7)" в качестве оператора сравнения между «b.get »и« char ».

template-test.cpp: In function ‘int main(int, char**)’: 
template-test.cpp:16:17: error: invalid use of non-static member function 
    std::cout << b.get<char>(7) << std::endl; 
       ^
template-test.cpp:16:21: error: expected primary-expression before ‘char’ 
    std::cout << b.get<char>(7) << std::endl; 
        ^

(Это GCC 4.9, другие говорят, что-то подобное)

это должно ли работать?

Обход, который я нашел, заключался в том, чтобы объявить шаблонный «get» как в базе, так и в производном классе.

ответ

9

В производном классе имя get скрывает в базовом классе имя get. Следовательно, шаблон функции get() не найден при выполнении поиска по имени, и компилятор может интерпретировать только те токены, которые вы видели.

Вы можете использовать using декларации в своем классе Bar поправит:

class Bar : public Foo { 
public: 
    using Foo::get; 
// ^^^^^^^^^^^^^^^ 
    virtual int get() { return 3; } 
}; 

Вот live demo on Coliru.

Если вы не можете изменить определение Bar, потому что он не находится под вашим контролем, я думаю, вы могли бы претендовать на вызов get():

std::cout << f.Foo::get<char>(7) << std::endl; // get() template is found now. 

Смотрите here для живой демонстрации. Другой вариант заключается в выполнении вызова через указатель или ссылку на Foo:

Bar b; 
Foo& f = b; 
std::cout << f.get<char>(7) << std::endl; // get() template is found now. 

Еще раз, live example.

+0

Эта «перегрузка в базовый класс» - это то, о чем я слышал, но, очевидно, не думаю об этом достаточно часто. Спасибо за урок. –

+0

@PhilippT: Я думаю, вы можете искать «сокрытие имени», чтобы узнать больше об этом. Cheers :) –

+0

Как насчет 'std :: cout << b.Foo::get (7) << std :: endl;'? –

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