Візьмемо один приклад, скажімо, з якої причини ви хочете мати шаблон шаблону:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
Якщо ви компілюєте цей код із Visual Studio - він працює нестандартно. gcc призведе до помилки лінкера (якщо один і той самий файл заголовка використовується з декількох .cpp-файлів):
error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here
Можна перенести реалізацію у файл .cpp, але тоді вам потрібно оголосити такий клас, як -
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
template <>
void DemoT<int>::test();
template <>
void DemoT<bool>::test();
// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;
І тоді .cpp буде виглядати приблизно так:
//test_template.cpp:
#include "test_template.h"
template <>
void DemoT<int>::test()
{
printf("int test (int)\n");
}
template <>
void DemoT<bool>::test()
{
printf("int test (bool)\n");
}
Без двох останніх рядків у файлі заголовка - gcc буде добре працювати, але Visual studio видасть помилку:
error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function
Синтаксис шаблону класу необов’язковий у випадку, якщо ви хочете розкрити функцію за допомогою експорту .dll, але це застосовно лише до платформи Windows - тому test_template.h може виглядати так:
//test_template.h:
#pragma once
#include <cstdio>
template <class T>
class DemoT
{
public:
void test()
{
printf("ok\n");
}
};
#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
template <>
void DLL_EXPORT DemoT<int>::test();
template <>
void DLL_EXPORT DemoT<bool>::test();
з .cpp-файлом з попереднього прикладу.
Однак це призводить до більшої болі головного болю для лінкера, тому рекомендується використовувати попередній приклад, якщо ви не експортуєте .dll функцію.