#опытным
Во влажных мечтах С++ программистов всегда находится место для возможностей одновременного использования статического и динамического полиморфизмов. И тут прям напрашивается иметь виртуальный шаблонный метод. Давайте напишем:
struct Base
{
template <typename T>
virtual void do_something(T arg) = 0;
virtual ~Base() = default;
};
struct Derived : Base
{
template <typename T>
void do_something(T arg) override
{
// do something
}
};
Выглядит привычно, пробуем скомпилировать.... И оно не билдится.
С++ не разрешает вам иметь виртуальный шаблонный метод.
Но почему?
Надо понимать, как под капотом работают виртуальные и шаблонные функции.
При определении шаблона, никакой низкоуровневый код не генерируется. Код генерируется только, когда компилятор видит использование шаблона с каким-то конкретным типом. Подробнее можно тут почитать.
Так вот реальный код инстанциаций шаблона может быть раскидан по очень большому множеству единиц трансляции.
Теперь про виртуальные функции. В абсолютном большинстве компиляторов они реализованы через vtable. Подробнее тут. Но вкратце: во время компиляции класса с виртуальным формируется статический массив, состоящий из адресов скомпилированных виртуальных методов. Порядок нахождения в массиве определяется порядком объявления методов в классе.
Почему вообще возможна такая генерация? Потому что компилятор уже в этой конкретной единице трансляции знает весь набор виртуальных методов в базовом классе и в наследнике. Поэтому он заранее может выбрать правильный размер vtable.
Теперь пытаемся совместить. Для генерации vtable на этапе компиляции нам нужно знать весь набор виртульных методов. И это прямо противоречит тому факту, что шаблон ничего не знает о своих потенциальных инстанциациях, которые разбросаны по куче единиц трансляции. Каждая единица трансляции компилируется независимо, поэтому получить информацию об адресах конкретных инстанциаций из других TU невозможно.
Хорошо, что в С++ есть множество других инструментов и концепций, которые помогут решить вашу техническую проблему в без виртуальных шаблонных методов. Это type erasure, crtp, visitor, std::function и std::any.
Combine the incompatible. Stay cool.
#cppcore #interview