Это явно указано в стандарте языка в 14.6.1 / 1:
В рамках шаблона класса,
когда имя шаблона
ни квалифицированный, ни сопровождаемый <,
это эквивалентно названию
шаблон сопровождается
параметры шаблона заключены в <>.
Это было переформулировано (через концепцию «введенного имени класса») в более поздних версиях стандарта, но суть в том, что это поведение явно изложено в документе.
Чтобы ответить на вторую часть вашего вопроса, это правило также применяется к объявлениям параметров при написании определений методов вне класса, но оно не применяется к объявлениям возвращаемых типов. Например, этот код ОК
template <typename T> struct S {
S foo(S);
};
template <typename T> S<T> S<T>::foo(S s) {
/* whatever */
}
, но вы не можете удалить бит <T>
из возвращаемого типа в определении метода. (И вы не можете удалить <T>
из полного имени метода.)
Что касается конкретно конструктора: вы должны использовать полное имя (с <T>
) для класса, но вы не должны использовать <T>
в имени самого конструктора. Таким образом, самая короткая форма для определения внеклассного в вашем случае будет
template <typename T> Wrapper<T>::Wrapper(const Wrapper& w) : t_(w.t_)
{
}
Обратите внимание, что вы не можете добавить бит <T>
к имени конструктора, даже если вы хотите
template <typename T> Wrapper<T>::Wrapper<T>(const Wrapper& w)
^ ERROR !!!
P.S. Последнее требование требует дальнейшего изучения. Компилятор Comeau Online считает, что это ошибка, а GCC считает, что все в порядке. Я вернусь к этому позже.
P.P.S. Компилятор в MSVC ++ 2005 жалуется на последнее объявление с предупреждением
warning C4812: obsolete declaration style: please use 'Wrapper<T>::Wrapper' instead
Интересно ...