Требуются ли аргументы шаблона везде при упоминании базового класса шаблона?

Вот простой шаблон;

template <class T>
class tt {
    private:
        T  x;
    public:
        tt() {x=0;};
        Add(T p) {x += p;};
};

... а затем его подкласс;

class cc : public tt<int> {

    public:
        cc() : tt() {};

};

Это нормально компилируется в VC, но не в C++ Builder (XE), где выдает ошибку E2102. Компилятору C++ Builder требуется следующий синтаксис конструктора класса cc для компиляции;

cc() : tt<int>() {};

Фактически, компилятору C++ Builder необходимо, чтобы параметры шаблона повторялись каждый раз, когда шаблон tt упоминается в классе cc.

Указывает ли стандартная спецификация C++ необходимость постоянного повторения параметров шаблона или компилятор C++ Builder ошибается?


person Frank E    schedule 01.11.2011    source источник
comment
tt — это шаблон. tt<int> — это тип. Вы можете наследовать только от типов.   -  person Kerrek SB    schedule 01.11.2011
comment
вы можете избежать повторений, используя typedef   -  person Roee Gavirel    schedule 01.11.2011
comment
@KerrekSB, разве tt не относится к введенному имени класса из tt<int>?   -  person avakar    schedule 01.11.2011
comment
Да, typedef — это план, если мне придется повторять параметры шаблона. Мне кажется странным, что определения нуждаются в повторениях, типа, заданного в class cc : public tt‹int›, должно быть достаточно, поскольку я не могу использовать другие параметры позже.   -  person Frank E    schedule 01.11.2011
comment
@avakar: я думаю, что это верно только для самого шаблона класса; т. е. если вы говорите template <typename T> class Foo;, то Foo относится к текущему экземпляру. Хотя я не уверен на 100%. Подождем авторитетного ответа :-)   -  person Kerrek SB    schedule 01.11.2011


Ответы (2)


С++ Builder здесь неправ. Причина, по которой вы должны иметь возможность использовать имя предка в списке инициализаторов членов конструктора, связана с концепцией внедренного имени класса.

Когда вы определяете класс, компилятор вставляет имя класса в этот класс и заставляет его ссылаться на самого себя. Это введенное имя позволяет вам использовать имя класса без аргументов шаблона внутри класса.

template <class T>
struct tt {
    // The compiler behaves as if there was the following.
    // typedef tt<T> tt;
};

Это внедренное имя ищется, когда вы используете имя tt в списке инициализаторов членов.

(Для справки, clang принимает фрагмент без аргумента шаблона.)

Бонус: если бы вы определили cc как шаблон класса с параметром шаблона T, а предок зависел бы от T, имя tt не было бы найдено в контексте списка инициализаторов элементов конструктора cc.

template <class T>
class cc : tt<T> {
    cc()
        : tt<T>() /* You must use <T> here. */
    {
    }
};
person avakar    schedule 01.11.2011
comment
+1 за правильный подробный ответ. Еще одно интересное следствие этого: stackoverflow.com/q/5315134/34509 - person Johannes Schaub - litb; 02.11.2011
comment
Итак, g++ не подходит для того, чтобы не вводить имя в дочерний класс? g++ 4.2 и 4.4, конечно, не подхватывают введенное имя. Есть ли ссылка на то, что введенные имена наследуются? - person Mark B; 02.11.2011
comment
@MarkB, технически, имена из базы не вводятся в дочерний класс; вместо этого алгоритм поиска предназначен для поиска имени в базовых классах, если это имя не может быть найдено в дочернем классе. g++ ошибается, не находя введенное имя дочернего элемента во время поиска. - person avakar; 02.11.2011
comment
Хорошо, приятно знать. Примечание; VC компилируется, даже если cc определен как шаблон (как в вашем примере, но без ‹T› в конструкторе), поэтому CBuilder, VC и gcc не могут (по-разному) сделать это правильно... - person Frank E; 02.11.2011
comment
@FrankE, да, VC известен тем, что выполняет определенные поиски в точке создания экземпляра, а не в точке определения шаблона. Как только cc<T> становится экземпляром cc<int>, базовый класс становится tt<int> и поиск tt завершается успешно. - person avakar; 02.11.2011

вы можете избежать повторений, используя typedef:

typedef tt<int> tti;

...

class cc : public tti {

    public:
        cc() : tti() {};

};
person Roee Gavirel    schedule 01.11.2011
comment
Это просто обходной путь. Однако на самом деле это не отвечает на вопрос о том, что определяет стандарт. - person Rob Kennedy; 01.11.2011
comment
Я знаю (и это мой план, если придется). Но почему параметры tt вообще должны повторяться? - person Frank E; 01.11.2011