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

Являются ли явные экземпляры шаблонов классов С++ для создания зависимых базовых классов?

Я понял, что явный запрос на создание экземпляра также автоматически создаст экземпляр всех элементов базового класса, но при создании этого кода с помощью Visual Studio 2008 или 2010 я получаю linker error: unresolved external symbol "public: void Base<int>::foo(int)".

Обратите внимание, что добавление вызова foo() внутри bar() заставляет компилятор создавать экземпляр Base<int>::bar(), и сборка завершается успешно, поэтому кажется, что компилятор имеет всю необходимую информацию для создания экземпляра foo().

Очевидно, что явное создание экземпляра Base<int> в source.cpp позволяет строить успешное выполнение, но кажется глупым необходимость явно создавать любые зависимые базовые классы всякий раз, когда явно создается экземпляр производного класса.

Это нормально? Я не мог найти, что говорит стандарт относительно этой проблемы.

header.h

template<typename T>
class Base {
public:
    void foo();
};

template<typename T>
class Derived : public Base<T> {
public:
    void bar();
};

source.cpp

#include "header.h"

template<typename T>
void Base<T>::foo() { }

template<typename T>
void Derived<T>::bar() {
    // this->foo();   // adding this forces instantiation of foo()???
}

template class Derived<int>;

main.cpp

#include "header.h"

int main() {
    Derived<int> d;
    d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)"
}

Edit:

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

Обратите внимание, что класс определяется классом-head {member-specification} и "Спецификация участника в определении класса объявляет полный набор членов класса, ни один член не может быть добавлен в другое место". Таким образом, члены находятся только между фигурными фигурными скобками {}, а члены базового класса public не становятся членами производного класса, они просто доступны из производного класса или объектов производного класса.

Мой единственный оставшийся вопрос заключается в том, почему стандарт указывает, что явное инстанцирование шаблона класса только создает экземпляры, а не элементы базовых классов? Я предполагаю, что это позволяет больше контролировать то, что получает явным образом экземпляр где-то. Кто-то, кто использует явные экземпляры класса шаблонов, скорее всего, будет иметь определения базового класса в другом файле, чем определения производного класса, и будет явно создавать экземпляры каждого отдельно.

4b9b3361

Ответ 1

В стандарте говорится

Явное инстанцирование специализации шаблона класса подразумевает создание экземпляров всех его элементов, которые ранее не были явно специализированы в блоке перевода, содержащем явное инстанцирование.

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

Явное инстанцирование, которое называет специализацию шаблона класса, также является явным такого же рода (декларация или определение) каждого из его членов (не считая членов, унаследованных от базы классы), которые ранее не были явно специализированы в блоке перевода, содержащем явные экземпляр, за исключением случаев, описанных ниже. [Примечание. Кроме того, обычно это будет явное некоторые зависящие от реализации данные о классе. - конечная нота]