Как правильно явно создать экземпляр класса шаблона с полностью специализированными членами?

Допустим, у нас есть следующие файлы:

foo.h

namespace ns
{
    template <typename T>
    class Foo
    {
    public:
        Foo();

        ~Foo();

        void DoIt();
    };
}

foo.cpp

#include "foo.h"

#include <iostream>

namespace ns
{
    template <typename T>
    Foo<T>::Foo() { std::cout << "Being constructed." << std::endl; }

    template <typename T>
    Foo<T>::~Foo() { std::cout << "Being destroyed." << std::endl; }

    template <>
    void Foo<int>::DoIt()
    {
        std::cout << "Int" << std::endl;
    }

    template <>
    void Foo<double>::DoIt()
    {
        std::cout << "Double" << std::endl;
    }

    template class Foo<int>;
    template class Foo<double>;
}

Это правильный способ сделать явное создание экземпляра, предполагая, что тип будет когда-либо использоваться только с int или double в качестве параметров типа? Или вам нужно также объявить явную специализацию в заголовочном файле?

Выполнение этого так, как я показал, работает с Visual Studio, но у коллеги были проблемы с GCC (хотя я только что проверил, и я думаю, что это связано с чем-то еще, но я все равно опубликую этот вопрос)


person Bwmat    schedule 14.04.2015    source источник
comment
Вам также нужно будет определить деструктор, поскольку вы его объявляете, и переместить определения конструктора и деструктора в заголовок, поскольку они являются шаблонами. Что касается специализаций, то они будут видны только в вашем .cpp файле.   -  person 101010    schedule 14.04.2015
comment
@ 101010 Нет необходимости перемещать c / dtor в заголовок, есть явное создание экземпляра.   -  person T.C.    schedule 14.04.2015
comment
@Т.С. На самом деле нет необходимости перемещать их в шапку, чтобы этот пример работал. Однако, поскольку это шаблоны, я бы переместил их в заголовок, как часть хорошей практики.   -  person 101010    schedule 14.04.2015
comment
Забыл про деструктор, спасибо за указание.   -  person Bwmat    schedule 14.04.2015
comment
@ 101010 - Одно из предположений здесь состоит в том, что набор типов, которые будут использоваться в качестве параметров типов для шаблона, хорошо известен и конечен.   -  person Bwmat    schedule 14.04.2015


Ответы (1)


[temp.expl.spec]/p6 (выделено мной):

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

На самом деле, если вы объедините их внутри одной TU, то и clang, и gcc выдадут ошибку. Вам необходимо объявить эти явные специализации.


И так как мы очень близки к этому, я также просто процитирую [temp.expl.spec]/p7, потому что я могу:

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

person T.C.    schedule 14.04.2015
comment
Весь смысл только в объявлении шаблона в заголовке и перемещении всей реализации (специализированной или нет) в файл cpp заключался в том, чтобы избежать неявного создания экземпляров. Без этого этот отрывок не применяется? - person Bwmat; 14.04.2015
comment
@Bwmat Вызов функции запускает неявное создание экземпляра объявления. - person T.C.; 14.04.2015
comment
... и т. д.?? ВТФ? :-) - person alain; 14.04.2015
comment
@alain Последняя строка - лимерик. Предыдущий текст был вставлен, чтобы скрыть его. - person dyp; 14.04.2015
comment
@dyp Тоже нормативный лимерик. - person T.C.; 14.04.2015
comment
Почему вы не упомянули явные объявления создания экземпляров (extern template)? - person dyp; 14.04.2015
comment
Спасибо @dyp, я действительно думал, что это цитата из стандарта. Не удивлюсь, если найду там что-то подобное ;-) - person alain; 14.04.2015
comment
@alain Это это цитата из Стандарта. Стандарт содержит этот лимерик (и текст, скрывающий его). - person dyp; 14.04.2015
comment
@dyp Учитывая текущую структуру кода в ОП, я не думаю, что extern template многого добавит (если вообще добавит). - person T.C.; 14.04.2015
comment
Я думал, вам нужно использовать extern template, чтобы использовать эти экземпляры в единице перевода != foo.cpp? - person dyp; 14.04.2015
comment
@dyp Нет, это просто экономит вам дополнительные экземпляры. - person T.C.; 14.04.2015
comment
Я немного запутался: Стандарт говорит (ИМХО, немного расплывчато), что odr-использование функции вызывает ее создание экземпляра. В нем не говорится, что делает эта инстанцирование (создает определение или декларацию?). Если определение шаблона функции недоступно в TU, текущие g++ и clang++ выполняют компиляцию TU, которая неявно создает его экземпляр, но терпит неудачу при компоновке (независимо от того, существует ли явное объявление создания экземпляра). Они принимают программу, содержащую любые экземпляры для того же набора аргументов templ в другой TU. Это законно? - person dyp; 14.04.2015
comment
@dyp [temp]/6: шаблон функции, функция-член шаблона класса, шаблон переменной или статический член данных шаблона класса должен быть определен в каждой единице перевода, в которой он неявно создан (14.7.1), если только соответствующая специализация явно реализуется (14.7.2) в некоторой единице перевода; диагностика не требуется. - person T.C.; 14.04.2015