Шаблон поиска в классе? - PullRequest
       27

Шаблон поиска в классе?

2 голосов
/ 10 ноября 2009

Трудно получить слово для этого. Иногда я вижу такой класс:

template <typename T>
class Wrapper
{
public:
    Wrapper(const T& t) : t_(t) {}
    Wrapper(const Wrapper& w) : t_(w.t_) {}
private:
    T t_;
}

Насколько я могу судить, это законный код. Однако, почему конструктору копирования разрешено принимать const Wrapper& без явного указания, что ему нужен const Wrapper<T>&. Когда еще подразумевается тип шаблона? Разрешено ли писать конструктор копирования таким образом, если вы не используете определение в классе?

Ответы [ 4 ]

3 голосов
/ 10 ноября 2009

Это явно указано в стандарте языка в 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

Интересно ...

3 голосов
/ 10 ноября 2009

По сути, внутри определения шаблона класса вам разрешено использовать template-name для шаблона, определяемого как сокращение для полной параметризованной версии template-id .

0 голосов
/ 10 ноября 2009

Нет, вне класса вы должны написать:

template <typename T>
Wrapper<T>::Wrapper<T>(const Wrapper<T>& w) : t(w.t) {}

Но внутри класса Wrapper означает «текущий класс».

РЕДАКТИРОВАТЬ: Это для Эндрю и его исследования, почему компилятор отклонил конструктор:

template <typename T>
class Foo {
public:
    Foo() {}
    Foo(const Foo& f);
};

template <typename T>
Foo<T>::Foo<T>(const Foo<T>& f) { }

int main(int argc, char** argv)
{
    Foo<int> f;
    Foo<int> g(f); // make sure the template is instantiated
}
0 голосов
/ 10 ноября 2009

В шаблонном классе, подобном этому, использование имени класса аналогично использованию Wrapper<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...