Концептуально, на самом высоком уровне
template <Type value, class Y, ...>
...fn-or-class...
можно с пользой сравнить с
#define FN_OR_CLASS(VALUE, TYPE_Y, ...) \
...fn-or-class...
Оба в основном ждут вызова / создания экземпляра, а затем заменяют указанные типы и значения для создания специализированного кода.с полной оптимизацией во время компиляции для этих значений.Но шаблоны отличаются от #defines тем, что они являются правильными конструкциями этапа компиляции, которые могут быть заключены в пространства имен, должны удовлетворять лексеру, и не весь шаблон класса генерируется при первом рассмотрении, а скорее генерируются функциипо мере необходимости.
Когда компилятор впервые встречает шаблон, он выполняет грубую проверку того, что содержимое шаблона может иметь смысл для некоторой гипотетической реализации.Позже, когда он встречает конкретную реализацию, тогда для шаблонов классов дополнительно проверяются только те функции, которые используются , чтобы убедиться, что они могут быть скомпилированы с конкретными параметрами, которые используются.Это означает, что шаблон класса может появиться - для некоторого ограниченного использования - для поддержки создания экземпляров с определенными параметрами, но если вы начнете использовать некоторые другие функции в API-интерфейсе шаблона, то внезапно вы обнаружите, что он не может быть скомпилирован с этим предполагаемымподходящий параметр ... может заставить вас изменить дизайн использования довольно поздно в день.Это одна из причин, по которой C ++ 0x планировал ввести Концепции: они элегантно позволяют шаблонам проверять, соответствуют ли параметры всем ожиданиям шаблона - если они допускают какую-либо реализацию, то пользователь может предположить, что полный API шаблона может
template <class T>
struct X
{
void f() { }
void g() { T::whatever(); } // only error if g() called w/o T::whatever
};
int main()
{
X<int> x;
x.f();
// x.g(); // would cause an error as int::whatever() doesn't exist...
}
Метод SFINAE (ошибка замещения не является ошибкой) может затем позволить компилятору выбирать между несколькими почти совпадающими функциями на основе фактических параметров экземпляра шаблона.Это может быть использовано для реализации базового самоанализа во время компиляции, такого как «имеет ли этот класс функцию-член fn (int)?».