我目前正在尝试按照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 年开始似乎有一个相关的问题,但据我所知,它不包含Variant 4,我认为编译器错误现在已经修复。;)
还有这个问题,让我觉得Variant 3应该是那个,g++接受Variant 1是一种礼貌。
我在底部包含了完整的精简测试应用程序;它应该按照提供的方式编译(注释适当的行)。
变体 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 对 Variant 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)'
完整的测试应用程序
由于auto关键字,需要-std=c++0x和 g++。
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;
}