Почему использование typedef в этом шаблоне необходимо? - PullRequest
3 голосов
/ 01 августа 2009

Когда я компилирую этот код в Visual Studio 2005:

  template <class T>
  class CFooVector : public std::vector<CFoo<T>>
  {
  public:
    void SetToFirst( typename std::vector<CFoo<T>>::iterator & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>>::iterator & iter )
  {
    iter = begin();
  }

Я получаю эти ошибки:

c:\home\code\scantest\stltest1\stltest1.cpp(33) : error C2244:     'CFooVector<T>::SetToFirst' : unable to match function definition to an existing declaration
    c:\home\code\scantest\stltest1\stltest1.cpp(26) : see declaration of 'CFooVector<T>::SetToFirst'
    definition
    'void CFooVector<T>::SetToFirst(std::vector<CFoo<T>>::iterator &)'
    existing declarations
    'void CFooVector<T>::SetToFirst(std::_Vector_iterator<_Ty,_Alloc::rebind<_Ty>::other> &)'

Если я добавлю typedef в шаблон CFooVector, я смогу получить код для компиляции и работы:

  template <class T>
  class CFooVector : public std::vector<CFoo<T>>
  {
  public:
    typedef typename std::vector<CFoo<T>>::iterator FooVIter;
    void SetToFirst( FooVIter & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( FooVIter & iter )
  {
    iter = begin();
  }

У меня вопрос: почему typedef работает, когда не используется объявление 'typename std::vector>::iterator'?

Ответы [ 5 ]

5 голосов
/ 01 августа 2009

Это также компилируется и раскрывает источник путаницы VC ++ - тип распределителя. Видимо за пределами класса VS выбирает разные значения по умолчанию. Или, может быть, он не может признать их одинаковыми.

Компилируется на VS2008 (как есть) и VS2003 (с пробелом между >>)

template <class T>
class CFoo
{
public:
    T m_t;
};

template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
    void SetToFirst(typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter);

};

template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter )
{
    iter = begin();
}

GCC 3.4 хотел this-> begin () и пробел, но в противном случае он может компилировать код без явного типа распределителя ... Определенно выглядит компилятор MS не так умно, как должно быть ...

2 голосов
/ 01 августа 2009

Вопрос на самом деле не в typedef, а в typename.

Всякий раз, когда компилятор встречает имя, которое зависит от шаблона (в основном, все, что использует :: после шаблона, он не может определить, является ли это тип или значение (это может быть, например, статическое int ), так что нужна подсказка.

Когда вы добавляете typename, вы указываете, что зависимый член на самом деле является типом.

В вашем примере с typedef у вас все еще есть typename в объявлении typedef, но после объявления typedef это имя не является зависимым. Это просто тип, поэтому typename не требуется при обращении к typedef.

По сути, компилятор не может быть уверен, что std::vector<CFoo<T>>::iterator является типом.

Но он знает, что FooVIter это тип, потому что это typedef. Typedefs всегда являются типами.

1 голос
/ 01 августа 2009

typename является самым важным ключевым словом здесь.

Важно отметить:

>>

должен иметь пробел между ними, чтобы не вводить компилятор в заблуждение, что вы используете

operator>>

Без вашего полного кода я не знаю, почему возникает проблема после использования typename. Может быть, вам это не нужно в определении вне определения класса?

Также может быть лучше сделать:

template <typename T>

вместо

template <class T>

Кстати, не следует извлекать уроки из классов STL, если вы не очень, очень осторожны.

Классы STL не имеют виртуальных деструкторов.

0 голосов
/ 01 августа 2009

Еще один интересный момент: VS2008 компилирует вашу вторую попытку, если вы не используете квалификацию std:: для vector в определении SetToFirst():

  template <class T>
  class CFooVector : public std::vector< CFoo<T> >
  {
  public:
      void SetToFirst( typename std::vector< CFoo<T> >::iterator & iter );
  };

  template <class T>
  void CFooVector<T>::SetToFirst( typename /*std::*/vector< CFoo<T> >::iterator & iter )
  {
    iter = begin();
  };

Обратите внимание, что казалось, что имеет значение только определение, а не декларация. Мне также было интересно, что не имеет значения, был ли "using namespace std;" или нет ...

Я действительно не знаю, что с этим делать.

0 голосов
/ 01 августа 2009

Кажется, отлично работает для меня , если Я делаю следующие изменения -

template <class T>
class CFoo
{
public:
T m_t;
};

template <class T>
class CFooVector : public std::vector< CFoo<T> >
{
public:
void SetToFirst( typename std::vector<CFoo<T> >::iterator & iter );
};

template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T> >::iterator & iter )
{
iter = begin();
}

Я в основном изменил std::vector<CFoo<T>> на std::vector<CFoo<T> >, иначе компилятор (в моем случае gcc) распознает его как оператор >>.

...