Как известно, с помощью директив явного инстанцирования можно несколько ослабить зависимость файлов. Но вот возник интересный вопрос в связи со специализацией методов и статических элементов. Пока все в одном файле или объединяется по модели включения — проблем нет. А вот в модели явного инстанцирования некоторые проблемы возникают
На примере:
//Листинг 11.6. Модель явного инстанцирования при наличии специализаций
//-------------- файл Static.h
#pragma once
template <class T>
class Static
{ static T t; // имя, зависимое от параметра шаблона
static int count; // независимое имя
public:
Static (){ ++count; } // конструктор считает объекты
Static ( const Static &r ) // конструктор считает объекты
{ *this = r; ++count; }
~Static (){ --count; } // деструктор
void set( T x = T() );
static void print();
};
//-------------- файл StaticDef.h
#include <iostream>
#include <string>
using namespace std;
#include "Static.h"
// стандартные определения
template <class T> int Static<T>::count = 0; // счетчик объектов
template <class T> T Static<T>::t = T(); // определение t
template <class T> // общая реализация метода
void Static<T>::set( T x = T() ) { t = x; }
template <class T> // общая реализация метода
void Static<T>::print( ) { std::cout << t <<" "<< count; }
// специализации статического поля t для чисел
template <> int Static<int>::t = 15;
template <> double Static<double>::t = 121;
// специализация для строк
template <> string Static<string>::t = "Agayn Hello!";
template <>
void Static<string>::print()
{ std::cout << t <<' '<< t.length() << ' '; }
// специализация для строковых констант
template <> const char * Static<const char *>::t = "Hello!";
template <>
void Static<const char *>::print( )
{ std::cout << t <<' '<< strlen( t ) << ' '; }
//-------------- файл StaticInst.cpp
// файл с директивами явного инстанцирования
#include "StaticDef.h"
template class Static<int>;
template class Static<long>;
template class Static<double>;
template class Static<const char *>;
//-------------- файл Main.cpp
#include <iostream>
#include <string>
using namespace std;
#include "Static.h"
Static<long> r;
int main()
{ setlocale(LC_ALL, "Russian");
// объектов типа Static<double> не существует
Static<double>::print(); cout << endl; // вывод: 121 0
Static<double> r; // локальный объект создан
Static<double>::print(); cout << endl; // вывод: 121 1
r.set( 234 );
Static<double>::print(); cout << endl; // вывод: 234 1
r.print(); cout << endl; // вывод: 234 1
// один объект типа Static<long> уже существует!
::r.print(); cout << endl; // вывод: 0 1
Static<long>::print(); cout << endl; // вывод: 0 1
// объектов типа Static<int> не существует
Static<int>::print(); cout << endl; // вывод: 15 0
Static<int> t; // локальный объект создан
t.print(); cout << endl; // вывод: 15 1
t.set( 1234 );
Static<int>::print(); cout << endl; // вывод: 1234 1
// объектов типа Static<const char *> не существует
Static<const char *>::print(); cout << endl; // вывод: Hello 6
Static<const char *> S; // локальный объект создан
S.set( "Привет" );
S.print(); cout << endl; // вывод: Привет 6
// объектов типа Static<const char *> не существует
Static<string>::print(); cout << endl; // вывод: Again Hello 12
}
Я всегда думал, что специализация статического поля или метода приводит к инстанцированию всего класса. Однако модель с явным инстанцированием этого не подтверждает — именно поэтому в файле с директивами явного инстанцирования StaticInst.cpp пришлось написать директивы и для int, и для double, и для long, и для const char *. А вот для string этого не понадобилось, поскольку объекты типа string не создаются и метод set не вызывается.
В стандарте внятных слов на тему специализации полей и методов в сочетании с явным инстанцированием не нашел.
Может все же там об это есть? Кто-нить знает?
Кстати, Visual C++.NET 2005 позволяет писать директивы явного инстанцирования без слова class, например
template Static<int>;
template Static<long>;
template Static<double>;
template Static<const char *>;
ИМХО, ошибка, поскольку по стандарту директива имеет синтаксис
template объявление