Он должен иметь отдельные предложения template
для каждого используемого шаблона. Здесь задействованы два шаблона, которые все заслуживают своих (не пустых) предложений шаблонов:
- Шаблон класса
Foo
- Шаблон конструктора
Рассмотрим этот случай, который не срабатывает из-за неоднозначности того, где параметр U
принадлежит
template<typename T>
struct A {
template<typename U> void f();
};
template<typename T, typename U>
void A<T>::f() { }
Теперь, что случилось с параметром U
? Конечно, компилятор может догадаться, что он может принадлежать f
, но догадка - это не то, что нравится компилятору :). Существующее правило гласит, что в зависимости от вложенности шаблонов предложения шаблонов отображаются в правильном порядке. Тогда все ясно.
Даже если кто-то придумает правило, как сопоставлять параметры с аргументами задействованных шаблонов (пока я не вижу реальной трудности в этом), это будет противоречиво. Поскольку на данный момент одно предложение шаблона перечисляет все параметры, которые принимает соответствующий шаблон. Очень похоже на список параметров функции. Если бы мы поместили все в одно предложение, эта четкая семантика могла бы быть нарушена - не говоря уже о том, что когда мы снова поместим определение в класс, шаблон вдруг получит свое собственное предложение:
// provides arguments for A's parameters, then for f ones
// when it's called
A<int> a;
a.f<bool>();
Это гораздо более естественно, когда у нас есть отдельные предложения шаблона, которые улавливают для каждого свои аргументы. Таким образом, синтаксис для указанного выше неправильного определения:
template<typename T>
template<typename U>
void A<T>::f() { }
Теперь также читатель кода сразу видит, что это определение шаблона элемента, а не (потенциально случайно объявленный, но неиспользованный) второй параметр для A
.