带有默认参数的C ++模板

时间:2012-02-15 18:26:57

标签: c++ templates stl typedef

这是我第一次尝试使用迭代器实现自定义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()
{

}

我有几个问题:

  1. 为什么这不编译? (错误C2143语法错误:'token2'之前缺少'token1')
  2. 为什么我必须明确提名所有模板参数,即使是默认模板参数? (考虑到Allocator有一个默认值,我不能只指定T?)
  3. 在这种情况下将标题与实现分开是正确的吗?

2 个答案:

答案 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)

  1. 出于以下几个原因:

    • SList<T,Allocator>::

    • 的返回类型iterator前面缺少begin
    • iterator是一种依赖类型,因此您需要在typename前面SList<T, Allocator>::iterator

    • 您不会从返回类型不是void的函数返回值;你需要归还一些东西。

  2. 因为名称是SList<T, Allocator>,您必须告诉编译器该类的全名,因为您需要能够引用类型名称Allocator,因为这只是怎么样。

  3. 你不能因为编译器要求模板的实现与声明在同一个文件中(除非你做了显式模板的通用性的显式实例化)。因此,您需要在最后将#include实现到接口文件中。