Проблема наследования шаблонов C ++ с базовыми типами - PullRequest
3 голосов
/ 21 сентября 2010

У меня есть следующий код, и он не может скомпилировать

template < typename T >
class Base
{
public:

    typedef T * TPtr;

    void func()
    {
    }
};

template < typename T >
class Derived : public Base< T >
{
public:
    using Base< T >::TPtr;
    using Base< T >::func;

    TPtr ptr;
};

int main( int c, char *v[] )
{
    Derived< int > d;
    d.func();
}

Компилятор выдает следующее.

t.cpp:16: error: 'TPtr' does not name a type
t.cpp:16: note: (perhaps 'typename Base<T>::TPtr' was intended)

Теперь я знаю, что могу просто сделать, как предлагает компилятор, ноЯ не могу понять, почему

    using Base< T >::TPtr;

не работает.

Если я закомментирую строку "TPtr ptr", то она компилируется, доказывая, что "using Base< T >::func;"Заявление работает.

Есть идеи?

Ответы [ 4 ]

9 голосов
/ 21 сентября 2010

Base< T >::TPtr - это так называемое зависимое имя , поэтому вам нужно добавить префикс к typename, чтобы объявление работало.

Кроме того, using не работаетс typename, поэтому вам нужно использовать typedef вместо:

typedef typename Base<T>::TPtr TPtr;

Проблема в том, что компилятор не может решить - не зная, что такое T!- будет ли TPtr в этом контексте называть тип или переменную / функцию.Чтобы избежать двусмысленности, он всегда предполагает последнее, если явно не указано иное (отсюда и необходимость typename).

2 голосов
/ 24 сентября 2010

Это часть дефекта.Хотя C ++ 03 действительно предоставил using typename, он не предоставил необходимые правила, чтобы сказать, что имя, объявленное объявлением using, является тип-именем.Он просто предоставил инструменту сказать, что имя, указанное в объявлении using, является именем типа.Таким образом, вы можете сделать на самом деле следующее, но с переменным успехом среди компиляторов.Некоторые заставят это работать, но некоторые не будут.

template < typename T >
class Derived : public Base< T >
{
public:
    using typename Base< T >::TPtr;
    using Base< T >::func;
      // up to here it's alright
    TPtr ptr;
      // but this may only work on some compilers
};

Эта проблема была исправлена ​​для C ++ 0x.Для C ++ 03 вместо этого можно использовать typedef.

1 голос
/ 21 сентября 2010

Я не могу понять, почему:
используя Base :: TPtr;
не работает.

Из-за возможной специализации шаблона, Base< T >::TPtr может быть любым: имя типа, имя переменной, функция и т. Д.

С ключевым словом typename вы сообщаете компилятору, что это может быть только имя типа.

Вот приличное объяснение того, какого рода двусмысленности он решает. Прокрутите вниз до «Проблема», она точно охватывает ваш случай.

0 голосов
/ 21 сентября 2010

когда пишешь TPtr ptr;

это выглядит как Base<T>::TPtr, и компилятор предположит, что это переменная-член Base<T> или метод Base<T> (это то, что он будет делать, потому что Base<T>::TPtr является «зависимым именем» и к сожалению, в этом случае компилятор примет переменную или функцию вместо типа), что сделает объявление недействительным.

Ключевое слово typename позволяет компилятору явно знать, что TPtr называет тип.

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