• c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters


    概念

    一个模板的参数是模板类型。

    举例

    c++11-17 模板核心知识(二)—— 类模板 中,如果我们想要允许指定存储Stack元素的容器,是这么做的:

    template <typename T, typename Cont = std::vector<T>> 
    class Stack {
    private:
      Cont elems; // elements
      ......
    };
    

    使用:

    Stack<double,std::deque<double>> dblStack;
    

    但是这样的缺点是需要指定元素类型两次,然而这两个类型是一样的。

    使用模板的模板参数(Template Template Parameters),允许我们在声明Stack类模板的时候只指定容器的类型而不去指定容器中
    元素的类型。例如:

    template <typename T, template <typename Elem> class Cont = std::deque>
    class Stack {
    private:
      Cont<T> elems; // elements
    public:
      void push(T const &); // push element
      void pop();           // pop element
      T const &top() const; // return top element
      bool empty() const {  // return whether the stack is empty
        return elems.empty();
      }
      ...
    };
    

    使用:

    Stack<int, std::vector> vStack;      // integer stack that uses a vector
    

    与第一种方式的区别是:第二个模板参数是一个类模板:

    template<typename Elem> class Cont
    

    默认值从std::deque<T>改为了std::deque.

    在C++17之后,模板的模板参数中的class也可以使用typename,但是不可以使用struct和union:

    template <typename T,
              template <typename Elem> typename Cont = std::deque>
    class Stack {       // ERROR before C++17
      ...
    };
    
    ......
    
    template<template<typename X> class C> // OK
    void f(C<int>* p);
    
    template<template<typename X> struct C> // ERROR: struct not valid here
    void f(C<int>* p);
    
    template<template<typename X> union C> // ERROR: union not valid here
    void f(C<int>* p);
    

    当然,由于模板的模板参数中的Elem没有用到,可以省略:

    template <typename T, template <typename> class Cont = std::deque> 
    class Stack {
      ...
    };
    

    另外注意一点,模板的模板参数中的模板参数,只能和模板的模板参数配合用。有点饶,举个例子:

    template<template<typename T, T*> class Buf>        // OK
    class Lexer {
        static T* storage;        // ERROR: a template template parameter cannot be used here
        ...
    };
    

    模板的模板参数的参数匹配 Template Template Argument Matching

    大家可以尝试自己编译一下上面的代码,可能会出现下列问题:

    error: template template argument has different template parameters than its corresponding template template parameter
    template <typename T, template <typename Elem> class Cont = std::deque>
    
    ...
    
    /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/deque:1197:1: note: too many template parameters in template template argument
    template <class _Tp, class _Allocator /*= allocator<_Tp>*/>
    

    意思是std::dequeCont不匹配。标准库的std::deque有两个参数,还有一个默认参数Allocator :

    template <class _Tp, class _Allocator = allocator<_Tp> > class _LIBCPP_TEMPLATE_VIS deque;
    

    解决办法一

    将Cont和std::deque的参数匹配即可:

    template <typename T,
              template <typename Elem, typename Alloc = std::allocator<Elem>>
              class Cont = std::deque>
    class Stack {
    ......
    };
    

    这里的Alloc没有用到,同样可以省略。

    成员函数定义举例:

    template<typename T, template<typename,typename> class Cont>
    void Stack<T,Cont>::push (T const& elem) {
        elems.push_back(elem);       // append copy of passed elem
    }
    

    解决办法二

    利用c++11-17 模板核心知识(四)—— 可变参数模板 Variadic Template

    template <typename T,
              template <typename......>
              class Cont = std::deque>
    class Stack {
    ......
    };
    

    但是,这点对于std::array无效,因为std::array的第二个参数是非类型模板参数 Nontype Template Parameters:

    // template<typename T, size_t N>
    // class array;
    

    假如使用 Stack<int,std::array> s;,那么编译器会报错:

    /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/array:126:29: note: template parameter has a different kind in template argument
    template <class _Tp, size_t _Size>
                                ^
    main.cc:22:33: note: previous template template parameter is here
              template <typename... Elem>
                                    ^
    

    (完)

    朋友们可以关注下我的公众号,获得最及时的更新:

    image

  • 相关阅读:
    51 nod 1109 01组成的N的倍数
    zoj 1530 Find The Multiple
    洛谷 P1124 文件压缩
    洛谷 P1270 “访问”美术馆(树形DP)
    洛谷 P1272 重建道路(树形DP)
    ♫【CSS】命名颜色
    【注释】
    -_-#【命名】BEM
    ☀【jQuery插件】DOM 延迟渲染
    ☀【组件】getRequest
  • 原文地址:https://www.cnblogs.com/zhangyachen/p/14083672.html
Copyright © 2020-2023  润新知