Подтвердить что ты не робот

Шаблоны функций-членов не могут быть объявлены виртуальными - из Addison Wesley: С++ Templates

От Addison Wesley: С++ Templates

Шаблоны функций-членов не могут быть объявлено виртуальным. Это ограничение потому что обычный реализация виртуальной функции call использует таблицу фиксированного размера с одной записью на виртуальную функцию. Однако количество экземпляров шаблона функции-члена не фиксируется до тех пор, пока вся программа не будет были переведены.

Указывает ли вышеуказанная цитата, что шаблоны имеют статическую привязку, а виртуальные функции имеют динамическое связывание, что причиной не может быть виртуальных шаблонов функций? Посмотрите, возможно ли объяснение на языке неспециалиста.

4b9b3361

Ответ 1

Рассмотрим:

struct X
{
    template <typename T>
    T incr(const T& t)
    {
        return t + 1;
    }
};

Поскольку incr() применяется к различным типам T, генерируются новые функции. Скажем, внутри app.c++ у вас есть:

X x;
x.incr(7);        // incr<int>()
x.incr(7.0);      // incr<double>()
x.incr("hello");  // incr<const char*>()

Затем, когда он компилирует app.c++, он видит 3 функции, которые - если incr разрешено быть virtual - это может сделать пространство для трех экземпляров, указанных выше в таблице виртуальной диспетчеризации для X. Тогда скажите, что он загружает общая библиотека во время выполнения, а код для этой библиотеки имел 2 экземпляра X::incr для uint32_t и std::string::const_iterator. dlopen() потребуется создать существующую таблицу виртуальной диспетчеризации для уже созданных объектов, чтобы создать пространство для двух новых функций. Не звучит слишком ужасно, но учтите:

  • каждый бит виртуальных функций, вызывающих код, должен знать, был ли адрес этих функций наложенным на некоторое смещение во время выполнения (из-за динамической загрузки дополнительных экземпляров), поэтому в каждой дополнительной памяти и производительности виртуальная отправка

  • когда на самом деле происходит множественное наследование или производный класс, компилятор может захотеть создать единую таблицу виртуальной диспетчеризации для общего набора виртуальных функций (один вариант, для реализации виртуальной диспетчеризации много): в этом случае новые виртуальные функции либо вытеснят виртуальные функции других классов, либо должны быть непересекающимися из существующих. Опять же, больше затрат времени на выполнение во всех схемах для управления этим.

Таким образом, очень редкие случаи, когда это может быть полезно, не стоит компрометировать и усложнять более распространенный случай не templated виртуальных.

Ответ 2

Да и нет.

Самый популярный метод разрешения вызовов виртуальных функций - использовать таблицу ( "vtable" ), где каждая виртуальная функция сопоставляется с индексом в таблице. Это более или менее требует, чтобы вы знали размер таблицы.

С помощью шаблонов новые функции будут созданы по мере необходимости в разных модулях. Затем вам придется либо убедить компоновщика построить таблицу после определения конечного числа функций, либо использовать какую-то структуру времени выполнения для поиска доступных функций во время выполнения.

Во многих системах компоновщик является частью ОС и ничего не знает о С++, поэтому опция ограничена. Разумеется, поиск во время выполнения влияет на производительность отрицательно, возможно, для всех виртуальных функций.

Итак, в конце концов, было решено, что просто не стоит беспокоиться о введении виртуальных шаблонов в язык.

Ответ 3

Означает ли приведенная выше цитата, что шаблоны имеют статическую привязку, а виртуальные функции имеют динамическое связывание, что причиной не могут быть шаблоны виртуальных функций?

В принципе, да. Более конкретно, статическое связывание вызывает проблему, когда код генерируется для поддержки динамической привязки.

Когда компилятор компилирует базовый класс, он находит виртуальную функцию и решает сделать таблицу виртуальных функций - это будет использоваться для реализации динамической привязки: когда виртуальная функция вызывается в производном экземпляре, скомпилированный код следует за указатель в экземпляре в таблицу виртуальных функций для производного класса, а затем указатель в этой таблице на реализацию виртуальной функции. Эта таблица должна включать все возможные виртуальные функции, которые можно было бы назвать. Теперь предположим, что мы создали шаблонную виртуальную функцию. Для таблицы функций нужна запись для каждого экземпляра шаблона, потому что любая из этих функций могла бы быть вызвана во время выполнения. Но информация о том, с какими типами создается экземпляр шаблона, не может (в общем) быть собрана в то время, когда генерируется таблица виртуальных функций. (По крайней мере, не обойтись без модели компиляции С++.)

Ответ 4

виртуальные функции и шаблоны все еще работают хорошо вместе, есть только небольшой частный случай, который не внедряется.

template<class T>
class A { virtual void f()=0; }; // works fine

class A { template<class T> virtual void f(T t)=0; }; // does not work

Ответ 5

Зависит от того, что вы подразумеваете под привязкой.

Вы можете реализовать виртуальный метод, вызвав шаблон-член. Пока вы встраиваете его, любой компилятор с оптимизацией хвостового вызова устраняет накладные расходы

Ответ 6

Сорта.

Вы не можете "переопределить" неиспользуемый template, потому что он вообще не существует в скомпилированном приложении. Если вы создаете экземпляр, то вы не переопределяете шаблон, а просто еще одну обычную функцию.: -)