Явное инстанцирование и специализация шаблонов
От: LaptevVV Россия  
Дата: 11.07.08 05:48
Оценка:
Как известно, с помощью директив явного инстанцирования можно несколько ослабить зависимость файлов. Но вот возник интересный вопрос в связи со специализацией методов и статических элементов. Пока все в одном файле или объединяется по модели включения — проблем нет. А вот в модели явного инстанцирования некоторые проблемы возникают
На примере:

//Листинг 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 объявление
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.