Ключевые слова шаблона и имя типа для внеклассового определения вложенного шаблона: VS 2012 и g++ 4.8.1, очевидно, не согласны

В настоящее время я пытаюсь реализовать итераторы для пользовательского шаблона класса контейнера, следуя подходу, описанному Dr.Dobb. Он работает нормально до того момента, когда я пытаюсь определить функции-члены итератора для вложенного итератора

template <typename T>
class Container
{
  template <bool isConst = false>
  class Iterator
  {
    Iterator& operator++();
    Iterator  operator++(int);  
  };
};

вне класса, как это:

template <typename T>
template <bool isConst>
//Container<T>::Iterator<isConst>& // g++ 4.8.1 is fine with that
typename Container<T>::Iterator<isConst>& // VS 2012 is fine with that
//typename Container<T>::template Iterator<isConst>& // again fine with g++
  Container<T>::Iterator<isConst>::operator++()
{
  ++index_;

  return *this;
}

template <typename T>
template <bool isConst>
//Container<T>::Iterator<isConst> // g++ 4.8.1 is fine with that
typename Container<T>::Iterator<isConst> // VS 2012 is fine with that
//typename Container<T>::template Iterator<isConst> // again fine with g++
  Container<T>::Iterator<isConst>::operator++(int)
{
  auto tmp(*this);

  this->operator++();

  return tmp;
}

До сих пор я был в состоянии идентифицировать три различных указанных варианта (подробно изложено ниже), которые будут работать с g++ 4.8.1 (с C++0x) или с Visual Studio 2012 (обновление 4), но не с обоими на в то же время.

Как правильно это сделать?

Похоже, что с 2009 года есть несколько связанный вопрос, но, насколько я могу судить, он не содержит Вариант 4, и я бы предположил, что ошибки компилятора уже исправлены.;)

И есть также этот вопрос, который заставляет меня думать, что Вариант 3 должен быть единственным, и принятие Варианта 1 g ++ является вежливостью.

Я включил мое полное урезанное тестовое приложение внизу; он должен компилироваться как предусмотрено (с соответствующими комментариями).

Вариант 1: нет ключевых слов

Container<T>::Iterator<isConst> // g++ 4.8.1 is fine with that

Для этого варианта VS жалуется, что зависимое имя не является типом, и предлагает использовать ключевое слово typename:

2>..\demo\demo.cpp(70): warning C4346: 'Container<T>::?$Iterator@$Q_N(*(_CAAB@))' : dependent name is not a type  
2>          prefix with 'typename' to indicate a type  
2>..\demo\demo.cpp(70): error C2143: syntax error : missing ';' before '&'  
2>..\demo\demo.cpp(70): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int  
2>..\demo\demo.cpp(70): error C2936: 'Container<T>::Iterator<isConst>' : template-class-id redefined as a global data variable  
2>..\demo\demo.cpp(70): fatal error C1903: unable to recover from previous error(s); stopping compilation  

Вариант 2: только ключевое слово typename

typename Container<T>::Iterator<isConst>& // VS 2012 is fine with that

Если используется только ключевое слово typename (как предлагает VS для варианта 1), g++ не слишком рад этому:

main.cpp:71:28: error: non-template 'Iterator' used as template                                                      
     typename Container<T>::Iterator<isConst>& // VS 2012 is fine with that  
                            ^                           
main.cpp:71:28: note: use 'Container<T>::template Iterator' to indicate that it is a template                        
main.cpp:71:28: error: expected unqualified-id at end of input 

Вариант 3: оба ключевых слова

typename Container<T>::template Iterator<isConst>& // again fine with g++

Если используются оба ключевых слова (как предложено в g ++ для варианта 2), VS снова будет жаловаться:

2>..\demo\demo.cpp(78): error C2244: 'Container<T>::Iterator<isConst>::operator ++' : unable to match function definition to an existing declaration  
2>          definition  
2>          'Container<T>::Iterator<isConst>  &Container<T>::Iterator<isConst>::operator ++(void)'  
2>          existing declarations  
2>          'Container<T>::Iterator<isConst>  Container<T>::Iterator<isConst>::operator ++(int)'  
2>          'Container<T>::Iterator<isConst> &Container<T>::Iterator<isConst>::operator ++(void)'  
2>..\demo\demo.cpp(92): error C2244: 'Container<T>::Iterator<isConst>::operator ++' : unable to match function definition to an existing declaration  
2>          definition  
2>          'Container<T>::Iterator<isConst> Container<T>::Iterator<isConst>::operator ++(int)'  
2>          existing declarations  
2>          'Container<T>::Iterator<isConst> Container<T>::Iterator<isConst>::operator ++(int)'  
2>          'Container<T>::Iterator<isConst> &Container<T>::Iterator<isConst>::operator ++(void)'  

Завершить тестовое приложение

Требуется -std= C++ 0x с g ++ из-за ключевого слова auto.

template <bool isConst, typename IsTrue, typename IsFalse>
struct Choose;

template <typename IsTrue, typename IsFalse>
struct Choose<true, IsTrue, IsFalse>
{
  typedef IsTrue type;
};

template <typename IsTrue, typename IsFalse>
struct Choose<false, IsTrue, IsFalse>
{
  typedef IsFalse type;
};

template <typename T>
class Container
{
public:
  template <bool isConst = false>
  class Iterator
  {
  public:
    typedef typename Choose<isConst, T const&, T&>::type reference;
    typedef typename Choose<isConst, T const*, T*>::type pointer;

    typedef typename Choose<isConst,
      Container<T> const*,
      Container<T>*>::type ObjectPointer;

    friend class Iterator<true>;

    Iterator(
      ObjectPointer object           = 0,
      unsigned long long const index = 0);

    Iterator(Iterator<false> const& other);

    Iterator& operator++();
    Iterator  operator++(int);  

  private:
    ObjectPointer object_;

    unsigned long long index_;
  };

  typedef Iterator<>           iterator;
  typedef Iterator<true> const_iterator;
};

template <typename T>
template <bool isConst>
Container<T>::Iterator<isConst>::Iterator(
  ObjectPointer object,
  unsigned long long const index)
  : object_(object)
  , index_ (index )
{}

template <typename T>
template <bool isConst>
Container<T>::Iterator<isConst>::Iterator(Iterator<false> const& other)
  : object_(other.object_)
  , index_ (other.index_ )
{}

template <typename T>
template <bool isConst>
//Container<T>::Iterator<isConst>& // g++ 4.8.1 is fine with that
typename Container<T>::Iterator<isConst>& // VS 2012 is fine with that
//typename Container<T>::template Iterator<isConst>& // again fine with g++
  Container<T>::Iterator<isConst>::operator++()
{
  ++index_;

  return *this;
}

template <typename T>
template <bool isConst>
//Container<T>::Iterator<isConst> // g++ 4.8.1 is fine with that
typename Container<T>::Iterator<isConst> // VS 2012 is fine with that
//typename Container<T>::template Iterator<isConst> // again fine with g++
  Container<T>::Iterator<isConst>::operator++(int)
{
  auto tmp(*this);

  this->operator++();

  return tmp;
}

int main(int, char*[])
{
  Container<int> c;

  Container<int>::iterator it(&c, 0);

  Container<int>::const_iterator cIt = it;

  Container<int>::const_iterator cIt0 = ++cIt;
  Container<int>::const_iterator cIt1 = cIt++;

  return 0;
}

0 ответов

Другие вопросы по тегам