Может ли шаблонный метод быть виртуальным или виртуальный метод быть шаблонным в C++
Что проверяют
Понимаете ли вы, как устроена vtable и когда инстанцируются шаблоны. В вопросе смешаны разные вещи, и их нужно развести. Следом обычно просят показать обходной путь, если нужна «виртуальная шаблонная» функция.
Как отвечать
Разделите три случая:
- шаблон функции-члена не может быть виртуальным:
template<class T> virtual void f(T);не скомпилируется, стандарт это прямо запрещает. Причина в vtable: её состав фиксируется при определении класса, а число инстанций шаблона заранее неизвестно и зависит от типов, которые подставят в разных единицах трансляции; - обычная виртуальная функция внутри шаблона класса возможна:
template<class T> class Base { public: virtual void f(T); };вполне законно. УBase<int>иBase<double>своя vtable с фиксированным набором функций; - шаблон не переопределяет виртуальную функцию: если в наследнике объявить шаблонную
f, она не станет override, и вызов через указатель на базу пойдёт в базовую версию.
Если нужно поведение «виртуального шаблона», есть проверенные решения:
- стирание типа: виртуальная функция принимает
std::any,std::functionили свой интерфейс, а невиртуальная шаблонная обёртка упаковывает аргумент и вызывает её; - закрытый набор типов:
std::variant<int, double, std::string>иstd::visit, либо паттерн «Посетитель» с перегрузкой под каждый тип; - статический полиморфизм: CRTP, если тип известен на этапе компиляции и vtable вообще не нужна.
Уточните, не про паттерн ли «Шаблонный метод» речь. Там сам алгоритм это невиртуальная публичная функция базового класса, а шаги виртуальные, часто private (идиома NVI).
Где спотыкаются
Говорят «шаблонный метод может быть виртуальным», имея в виду виртуальную функцию шаблона класса. Это разные сущности, и ответ без их разделения засчитывают как ошибку.
Не могут объяснить причину запрета и отвечают «так в стандарте». Ожидается рассуждение про vtable и раздельную компиляцию.
Забывают, что виртуальные функции шаблона класса на практике инстанцируются вместе с vtable, даже если их никто не вызывает. Если для какого-то T она не компилируется, сборка ломается.