GCC и наследование типов
От: Аноним  
Дата: 14.01.09 13:08
Оценка:
template<typename T>
struct uf
{
  typedef T type;
};

template<class T>
struct f: public uf<T>
{
  void operator()(type) const; // error: ‘type’ has not been declared|
};

template<class T>
struct f<T*>: public uf<T*>
{
  void operator()(type) const; // error: ‘type’ has not been declared|
};


void test()
{
  f<int> fi;
  f<int*> fpi;
}


Как быть? Приходится писать либо "typename uf<T*>::type", либо "using uf<T*>::type", что не удобно.

Почему не наследуется type от родителя автоматически?
Re: GCC и наследование типов
От: Аноним  
Дата: 14.01.09 13:35
Оценка:
А>Приходится писать либо "typename uf<T*>::type", либо "using uf<T*>::type".
Ошибся, второй вариант не рабочий.
Re: GCC и наследование типов
От: rg45 СССР  
Дата: 14.01.09 14:06
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как быть? Приходится писать либо "typename uf<T*>::type", либо "using uf<T*>::type", что не удобно.

А>Почему не наследуется type от родителя автоматически?

Основная идея такова: имена, используемые внутри определения шаблонов делятся на две категории — зависимые от параметров шаблона и независимые. Причем не предусматривается возможности использования одного и того же имени то как зависимого то как независимого при разных инстанцированиях шаблона. Короче говоря, из анализа определения одного только шаблона компилятору должно быть понятно является ли то или иное имя зависимым или нет. В твоем примере — type — это имя зависимое от параметра шаблона (надо объяснять почему?). Но эта зависимость в определении шаблона нигде не обозначена и компилятор пытается искать это имя за пределами шаблона и, не найдя совершенно законно выдает ошибку.

А чем тебе не нравится конструкция:
typedef typename uf<T*>::type type;
void operator()(type) const;

???
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: GCC и наследование типов
От: byleas  
Дата: 14.01.09 16:52
Оценка:
Здравствуйте, rg45, Вы писали:

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

almost offtoppic: Интересно, Comeau пропускает вышеуказанный код только в relaxed mode, а VC компилирует без замечаний даже с /Wall.

Кстати, сейчас заметил, что аналогичная проблема возникает при использовании std::*ary_function. Получается, типы result_type & ko можно использовать только в метапрограммировании и нельзя — в качестве параметров? Выглядит нелогично и жаль.
Re[3]: GCC и наследование типов
От: rg45 СССР  
Дата: 15.01.09 08:42
Оценка:
Здравствуйте, byleas, Вы писали:

B>Здравствуйте, rg45, Вы писали:


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

B>almost offtoppic: Интересно, Comeau пропускает вышеуказанный код только в relaxed mode, а VC компилирует без замечаний даже с /Wall.

VC хочет казаться добреньким, но в данном случае он не прав. Смотрим стандарт:

14.6.2/3
In the definition of a class template or a member of a class template, if a base class of the class template
depends on a template-parameter, the base class scope is not examined during unqualified name lookup
either at the point of definition of the class template or member or during an instantiation of the class template
or member. [Example:

typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has type double
};


В VC данный пример даже не компилируется:

A a; // error C2248: 'B<T>::A' : cannot access private typedef declared in class 'B<T>'

Если в этом примере подправить class B на struct B, чтоб пример компилировался, то ошибку VC можно вывести на печать:
std::cout << typeid(X<void>().a).name() << std::endl; //Output: int
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: GCC и наследование типов
От: Аноним  
Дата: 15.01.09 08:44
Оценка: 6 (1)
Здравствуйте, byleas, Вы писали:

B>Здравствуйте, rg45, Вы писали:


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

B>almost offtoppic: Интересно, Comeau пропускает вышеуказанный код только в relaxed mode, а VC компилирует без замечаний даже с /Wall.

Все объясняется очень просто в VC не реализована синтаксическая проверка шаблонного кода до его инстанцирования,
а у всех остальных это сделано.
Re[4]: GCC и наследование типов
От: byleas  
Дата: 15.01.09 10:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Все объясняется очень просто в VC не реализована синтаксическая проверка шаблонного кода до его инстанцирования,

Понятно. Хотя для явного инстанцирования ключик есть, /d1BforceInst
Re[3]: GCC и наследование типов
От: Юрий Жмеренецкий ICQ 380412032
Дата: 15.01.09 13:00
Оценка: 6 (1)
Здравствуйте, byleas, Вы писали:

B>Здравствуйте, rg45, Вы писали:


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

B>almost offtoppic: Интересно, Comeau пропускает вышеуказанный код только в relaxed mode, а VC компилирует без замечаний даже с /Wall.

C /Za должен (возможно от версии зависит) ругаться.
Re: GCC и наследование типов
От: Юрий Жмеренецкий ICQ 380412032
Дата: 15.01.09 13:04
Оценка: 9 (1)
Здравствуйте, Аноним, Вы писали:

А>
А>template<typename T>
А>struct uf
А>{
А>  typedef T type;
А>};

А>template<class T>
А>struct f: public uf<T>
А>{
А>  void operator()(type) const; // error: ‘type’ has not been declared|
А>};

А>template<class T>
А>struct f<T*>: public uf<T*>
А>{
А>  void operator()(type) const; // error: ‘type’ has not been declared|
А>};


А>void test()
А>{
А>  f<int> fi;
А>  f<int*> fpi;
А>}


А>Как быть? Приходится писать либо "typename uf<T*>::type", либо "using uf<T*>::type", что не удобно.


А>Почему не наследуется type от родителя автоматически?


Базовый класс 'uf' является зависимым от параметра шаблона. Такие классы не рассматриваются при поиске неквалифицированных имен (таких как 'type') в scope класса 'f' ни в точке определения шаблона, ни в точке инстанцирования (14.6.2/3).

Другими словами, приведенный код эквивалентен следующему:
template<class T>
struct f
{
  void operator()(UnknownType) const; 
};


Тем не менее, name lookup для 'UnknownType'(и 'type') будет произведен вне класса в объемлющем scope (и 'выше'). И если там такое имя будет найдено, то entity обозначаемая этим именем и будет связана с именем f::UnknownType (f<T>::type):
typedef char type;

template<typename T>
struct uf
{
  typedef T type;
};

template<class T>
struct f: public uf<T>
{
  void operator()(type) const; // здесь type - это 'char'
};


Связывание в этом случае происходит в точке определения шаблона класса 'f', поэтому для обнаружения ошибки не требуется его инстанцирования. Зависимые же имена разрешаются в точке инстанцирования шаблона, т.к. для поиска таких имен необходимо знать все параметры шаблона и всё что от них зависит (14.6.2/1, 14.6/8). Это необходимо т.к. например, имени 'uf<T>::type' для каких-нибудь специализаций может не существовать вообще.

Если же оно существует (для конкретного типа 'T'), то оно наследуется классом 'f' и доступно. Путей доступа (в scope 'f') существует несколько, например:
//
void operator()(typename f<T>::template uf<T>::type);

//
void operator()(typename f::template uf<T>::type);

//
void operator()(typename f::type);

//
void operator()(typename uf<T>::type);

// и т.п.

//
using typename /* любой тип из вышеперечисленных */; 
void operator()(type) const; 

// Вариант c using полностью эквивалентен такому (Draft 7.3.3/20):

typedef typename /*...*/ type;
void operator()(type) const;
dependent names
Re[2]: GCC и наследование типов
От: byleas  
Дата: 15.01.09 14:44
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>using typename /* любой тип из вышеперечисленных */;

Надо же, не знал о using typename. Век живи…
Re[3]: GCC и наследование типов
От: rg45 СССР  
Дата: 15.01.09 15:19
Оценка:
Здравствуйте, byleas, Вы писали:

B>Здравствуйте, Юрий Жмеренецкий, Вы писали:


ЮЖ>>using typename /* любой тип из вышеперечисленных */;

B>Надо же, не знал о using typename. Век живи…

Да знал. Это же обычный using declaration, используемый в частности для раширения области видимости имен из базовых классов на производные:
struct A 
{
  typedef int Integer;
};
struct B : A
{
  using A::Integer;
};

Просто в том случае, когда A и B — шаблоны, Integer — зависимое имя типа, и это нужно явно сказать с помощью слова typename:.
template<typename T>
struct A 
{
  typedef int Integer;
};
template<typename T>
struct B : A<T>
{
  using typename A<T>::Integer;
};
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: GCC и наследование типов
От: Аноним  
Дата: 17.01.09 18:19
Оценка:
Это оправдание недоразвитости языка C++.
Re[3]: GCC и наследование типов
От: rg45 СССР  
Дата: 17.01.09 18:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Это оправдание недоразвитости языка C++.


Что именно?
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: GCC и наследование типов
От: Roman Odaisky Украина  
Дата: 17.01.09 22:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>Просто в том случае, когда A и B — шаблоны, Integer — зависимое имя типа, и это нужно явно сказать с помощью слова typename.


Не нужно.

The keyword typename shall only be used in template declarations and definitions, including in the return type of a function template or member function template, in the return type for the definition of a member function of a class template or of a class nested within a class template, and in the type-specifier for the definition of a static member of a class template or of a class nested within a class template.

(14.6/5)

Хотя грамматика зачем-то позволяет using typename. Даже если так, всё равно необходимости указывать typename нет. typename помогает отличить тип от выражения, а после using стоит ни то, ни другое, а просто имя.
До последнего не верил в пирамиду Лебедева.
Re[5]: GCC и наследование типов
От: rg45 СССР  
Дата: 17.01.09 23:57
Оценка: +1
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, rg45, Вы писали:


R>>Просто в том случае, когда A и B — шаблоны, Integer — зависимое имя типа, и это нужно явно сказать с помощью слова typename.


RO>Не нужно.


RO>

The keyword typename shall only be used in template declarations and definitions, including in the return type of a function template or member function template, in the return type for the definition of a member function of a class template or of a class nested within a class template, and in the type-specifier for the definition of a static member of a class template or of a class nested within a class template.

(14.6/5)


RO>Хотя грамматика зачем-то позволяет using typename. Даже если так, всё равно необходимости указывать typename нет. typename помогает отличить тип от выражения, а после using стоит ни то, ни другое, а просто имя.


Ну уж нет, здесь ключевое слово typename имеет ключевое значение (простите за каламбур):
template<typename T>
struct B : T
{
  using T::X; //X без typename - не тип
  
   void f() {X();} //Ok
   X g(); //"ComeauTest.c", line 7: error: nontype "T::X" is not a type name
};
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: GCC и наследование типов
От: Юрий Жмеренецкий ICQ 380412032
Дата: 18.01.09 02:26
Оценка: 11 (2)
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, rg45, Вы писали:


R>>Просто в том случае, когда A и B — шаблоны, Integer — зависимое имя типа, и это нужно явно сказать с помощью слова typename.


RO>Не нужно.


RO>

The keyword typename shall only be used in template declarations and definitions, including in the return type of a function template or member function template, in the return type for the definition of a member function of a class template or of a class nested within a class template, and in the type-specifier for the definition of a static member of a class template or of a class nested within a class template.

(14.6/5)


Этот пункт не описывает все возможные вхождения, 'shall only' относится только к словам до первой запятой.

RO>Хотя грамматика зачем-то позволяет using typename. Даже если так, всё равно необходимости указывать typename нет.


Необходимо указывать:

14.6/3
A qualified-id that refers to a type and in which the nested-name-specifier depends on a template-parameter (14.6.2) shall be prefixed by the keyword typename to indicate that the qualified-id denotes a type, forming an elaborated-type-specifier(7.1.5.3).


В надвигающемся стандарте это изменили, введя понятие current instantiation и разрешив опускать 'typename' для зависимых имен, которые находятся в 'current instantiation':

14.6/3
When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) ... it shall be prefixed by the keyword typename, forming a typename-specifier.


Но даже с учетом этих правил указание 'typename' для 'A<T>::Integer' в примере все же требуется.
Re[2]: GCC и наследование типов
От: Аноним  
Дата: 18.01.09 13:20
Оценка:
Да, C++ — недоразвитый язык.

И для несоответствующего стандарту компилятора Visual C++ программы писать проще, так как стандарт перекладывает работу с компилятора на плечи программиста.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.