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

C++ template with default parameter

本文关键字:C++ 模板 参数 默认      更新时间:2023-10-16

这是我第一次尝试用迭代器实现自定义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. 在这种情况下,将头与实现分离是正确的吗

1)

template<typename T, class Allocator>
typename SList<T,Allocator>::iterator SList<T,Allocator>::begin()
^^^^^^^^

这很烦人,但要习惯它。编译器假设所有模板化的东西都是变量,所以如果它是一个类型,你必须明确地说。

2) 编译器需要知道函数定义是针对具有两个模板参数的SList类的,并且这两个参数都可以是任何东西,这不是专门化。我知道你的是默认的,如果没有默认的,也不会模棱两可,但我认为这主要是为了简化编译器。

3) 定义可以在一个单独的文件中,但不能在它自己的"翻译单元"(一个编译的文件.cpp及其包含)中。所以,不要把它放在.cpp中,这只是令人困惑。模板定义位于.incl文件中并不罕见,该文件包含在标头的底部。这让编译器很高兴,并且您仍然可以分离声明和定义。

  1. 原因如下:

    • begin 的返回类型iterator前面缺少SList<T,Allocator>::

    • iterator是一个依赖类型,所以在两个位置中,SList<T, Allocator>::iterator前面都需要typename

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

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

  3. 您不能这样做,因为编译器要求模板的实现与声明在同一个文件中(除非您进行显式实例化,从而削弱模板的通用性)。因此,您需要在最后将实现#include放入接口文件中。