Почему позиция явной реализации шаблона имеет значение

Скажем, я объявляю шаблон класса A в a.h

#include <iostream>

template<bool b>
class A {
public:
void print(std::ostream& out);
};

И определить метод печати в a.cpp (с явным указанием для true а также false)

#include "a.h"
template<bool b>
void A<b>::print(std::ostream& out) {
out << "A" << b;
}

template class A<true>;
template class A<false>;

Пример основной основной программы в main.cpp может быть

#include "a.h"
int main() {
A<true> a;
a.print(std::cout);
}

Небольшой проект выше компилируется просто отлично.

Вопрос: Если я поставлю явные экземпляры выше определения print метод (в a.cpp), код больше не компилируется, с обычным undefined reference to A<true>::print(...) ошибка.

#include "a.h"
template class A<true>;
template class A<false>;

template<bool b>
void A<b>::print(std::ostream& out) {
out << "A" << b;
}

Почему это так?

редактировать: Makefile для компиляции

main : main.o a.o
g++ main.o a.o -o main

main.o : main.cpp
g++ -c main.cpp

a.o : a.cpp
g++ -c a.cpp

5

Решение

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

Тем не менее, компиляторы не требуются для этого; на самом деле это прямо запрещено Стандартом:

(§14.7.2 / 9) Явное определение экземпляра, которое именует специализацию шаблона класса, явно создает экземпляр специализации шаблона класса и является явным определением экземпляра только тех членов, которые были определены в момент создания.

Я думаю, что причины этого включают следующее:

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

  • Когда шаблон косвенным образом в конкретном случае принимаются во внимание только специализации, определенные до момента создания; поэтому правило одинаково для неявных и явных реализаций.

8

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

template class A<true>;
template class A<false>;

та же самая причина почему обычно ожидается, что код шаблона определяется в самом заголовке. Чтобы выполнить явную реализацию, вы (компилятор) должны иметь возможность увидеть полное определение класса шаблона, что невозможно из вашего main.cpp,

тем не мение a.cpp имеет доступ ко всем определениям класса (здесь метод print), поэтому здесь работает явная реализация.

1

По вопросам рекламы [email protected]