Я специализирую функции-члены класса шаблона в заголовочном файле следующим образом:
#pragma once
#include <iostream>
template<class T>
struct Test
{
void Print() { }
};
template<>
void Test<int>::Print()
{
std::cout << "int" << std::endl;
}
Правильно ли помещать специализацию в заголовочный файл (не будучи встроенным), или он должен быть в файле cpp? Он прекрасно компилируется, как показано выше (с использованием VS2012), но я довольно удивлен, что не получаю несколько ошибок компоновщика определений.
ODR требует ровно одного определения для не встроенных функций, которые ODR используемый (это означает, что для функций он может быть вызван).
Цитирую n3485, [basic.def.odr]
4 Каждая программа должна содержать ровно одно определение
каждая не встроенная функция или переменная, которая используется в этом
программа; Диагностика не требуется.
Тогда есть исключение для шаблоны (т.е. не для функций):
[акцент мой]6 Может быть несколько определений типа класса […], шаблона класса, нестатического шаблона функции, статического члена данных
шаблона класса, функция-член шаблона класса или шаблонная специализация для
какие параметры шаблона не указаны в программе при условии, что […]
Явная специализация шаблона не является шаблоном. Например, явно специализированный шаблон класса — это класс (со странным именем). Следовательно, ваше предположение верно, и множественные определения для явно специализированных членов шаблонов классов нарушают ODR.
С g ++ 4.8.1 я даже получаю ошибку компоновщика в такой программе; Обратите внимание, что я использовал функцию ODR. Диагностика нарушения ODR не требуется.
Размещение специализации в заголовочном файле является канонической формой (как boost
делает), это не нарушает ODR.