这是我第一次尝试使用迭代器实现自定义STL兼容容器,但是我在使用模板语法和使用方面遇到了一些麻烦。 这是我的头文件的一部分:
namespace unstd {
template<typename T,class Allocator = std::allocator<T>>
class SList
{
public:
typedef typename Allocator::value_type value_type;
typedef typename size_t size_type;
typedef typename Allocator::template rebind<T>::other allocator_type;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename T* pointer;
typedef typename const T* const_pointer;
typedef typename ptrdiff_t difference_type;
typedef typename SList_Iterator_Forward<T> iterator;
typedef typename const SList_Iterator_Forward<T> const_iterator;
....
/*----- ITERATORS -------*/
iterator begin();
...
};}
让我们考虑例如begin()方法。我编写了以下(在.cpp文件中),但不编译:
template<typename T, class Allocator>
iterator SList<T,Allocator>::begin()
{
}
//neither the following compile
template<typename T, class Allocator>
SList<T,Allocator>::iterator SList<T,Allocator>::begin()
{
}
我有几个问题:
答案 0 :(得分:2)
1)
template<typename T, class Allocator>
typename SList<T,Allocator>::iterator SList<T,Allocator>::begin()
^^^^^^^^
这很烦人,但要习惯它。编译器假设所有模板化的东西都是变量,所以如果它是一个类型,你必须具体说。
2)编译器需要知道函数定义是针对具有两个模板参数的SList
类,并且两者都可以是任何东西,这不是特化。我发现你的默认设置是默认的,如果缺少默认设置则不会含糊不清,但我认为这主要是为了简化编译器。
3)定义可以在一个单独的文件中,但不在它自己的“翻译单元”(编译文件.cpp及其包含)中。所以,不要把它放在.cpp中,这只是令人困惑。模板定义在.incl文件中并不罕见,该文件包含在标题的底部。这使编译器感到高兴,并且您仍然将声明和定义分开。
答案 1 :(得分:1)
出于以下几个原因:
SList<T,Allocator>::
iterator
前面缺少begin
iterator
是一种依赖类型,因此您需要在typename
前面SList<T, Allocator>::iterator
您不会从返回类型不是void
的函数返回值;你需要归还一些东西。
因为名称是SList<T, Allocator>
,您必须告诉编译器该类的全名,因为您需要能够引用类型名称Allocator
,因为这只是怎么样。
你不能因为编译器要求模板的实现与声明在同一个文件中(除非你做了显式模板的通用性的显式实例化)。因此,您需要在最后将#include
实现到接口文件中。