шаблонный класс и соответствующий внешний шаблонный класс в том же модуле перевода

Это правильное использование шаблона extern в C ++ 11? (Может ли быть так, что extern template class и соответствующие template class виден в том же переводчике?)

// example.hpp:
#pragma once
template< typename T >
class C {
void f(T);
};
// question is about the next two lines
extern template class C< float >;
extern template class C< double >;
// example_def.hpp:
#include "example.hpp"template< typename T >
void C< T >::f(T) {
//... smth. practicable
}
// example.cpp:
#include "example_def.hpp"template class C< float >;
template class C< double >;
// other.hpp:
#pragma once
void g();
// other.cpp:
#include "other.hpp"#include "example.hpp"// maybe those two lines should be here instead?
void g() {
C< float >();
C< double >();
}
// main.cpp:
#include "example.hpp"#include "other.hpp"// ...and here?
int main() {
C< float >();
C< double >();
g();
return 0;
}

3

Решение

Да, оба extern template class спецификация (называется явная реализация декларация по стандарту) и template class спецификация (называется явная реализация определение по стандарту) может быть в той же переводной единице, если определение (без extern) следует декларации (с extern):

(§14.7.2 / 11) Если объект является предметом как явного объявления экземпляра, так и явного определения экземпляра в той же единице перевода, определение должно следовать за объявлением. Сущность, которая является предметом явного объявления экземпляра и которая также используется таким образом, который в противном случае вызвал бы неявное создание экземпляра (14.7.1) в модуле перевода, должна быть объектом явного определения экземпляра где-то в программе; в противном случае программа некорректна, диагностика не требуется. [Примечание: это правило применяется к встроенным функциям, даже если явное объявление экземпляра такого объекта не имеет другого нормативного эффекта. Это необходимо для того, чтобы гарантировать, что если адрес встроенной функции берется в модуле перевода, в котором реализация выбрала подавление внеполосного тела, другое тело перевода предоставит тело. — примечание конца] Явное объявление экземпляра не должно называть специализацию шаблона с внутренней связью.

(Акцент мой). Условия явное декларирование а также явное определение экземпляра определены здесь:

(§14.7.2 / 2) Синтаксис для явной реализации:

явная конкретизация:
externвыбирать template декларация

Существуют две формы явного создания экземпляра: явное определение экземпляра и явное объявление экземпляра. Явное объявление экземпляра начинается с ключевого слова extern.


Эффект этих явных реализаций как следует:

  1. Явное объявление экземпляра (с extern) мешает всем неявный экземпляры вступают в силу (за исключением встроенных функций и шаблона класса специализаций, §14.7.2 / 10).

  2. Явное определение экземпляра (без extern) вызывает инстанцирование не важно что, то есть он переопределяет явное объявление экземпляра (это также следует из §14.7.2 / 10).


Общие комментарии
Тот факт, что ваши явные объявления экземпляров находятся в заголовочном файле, который определяет шаблон, подразумевает, что кто-нибудь кто использует заголовочные файлы, чтобы использовать шаблон, либо должен будет добавить явное создание экземпляра определение, или, в качестве альтернативы, необходимо указать ссылку на код другого .cpp файл, который содержит такое явное определение экземпляра.

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

4

Другие решения

Основная идея extern Шаблоны должны поддерживать явное создание экземпляров обычно используемых экземпляров, а также поддерживать неявное создание экземпляров для менее часто используемых параметров. Например, std::basic_string<char> может быть явно создан, но std::basic_string<signed char> может быть оставлено для неявной реализации (фактическими мотивирующими примерами были IOStreams, для создания которых потребовалось значительное время, но на самом деле используются только две реализации).

Чтобы разрешить неявную реализацию, определение используемых шаблонов должно быть видно в каждой единице перевода, где используется шаблон. Если определение шаблона является видимым, по умолчанию компилятор предполагает, что ему необходимо неявно предоставить экземпляр. Используя extern Объявление шаблона сообщает компилятору, что конкретный экземпляр шаблона будет предоставлен некоторым модулем перевода.

Хотя ваше дело работает, даже не нужно объявлять extern Шаблоны: Когда компилятор использует экземпляр и не находит его определения, он будет предполагать, что экземпляр найден в некоторой единице перевода.

3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector