1.模板的模板参数
在C++中,模板的模板参数(Template Template Parameters)是一种特殊的模板参数,允许我们将另一个模板作为模板参数传递给一个模板。这种技术可以用于实现更灵活和通用的模板设计。
模板的模板参数使用两个 “template” 关键字来指示,其中第一个 “template” 用于声明模板参数,第二个 “template” 用于声明模板模板参数本身。通常情况下,还需指定模板模板参数的参数列表。
先观察一下示例:
template <typename T, typename CONT = std::vector<T>>
class Stack
{
private:
CONT elems;
public:
void push(T const&);
void pop();
T top() const;
bool empty() const
{
return elems.empty();
}
int32_t getElemsSize() const
{
return elems.size();
}
};
上面示例在使用的过程中,要不使用默认值,要不需要两次指定元素类型
Stack<int> int_stack; //使用默认值
Stack<double, std::deque<double>> double_stack; //指定两次元素类型double
然而,借助于模板的模板参数,可以指定容器的类型而不需要指定所含元素的类型,这样在声明的时候可以使用Stack<double, std::deque> double_stack
2.实现方法
为了实现上述的特性,需要将第2个模板参数指定为模板的模板参数,那么Stack的声明如下:
template <typename T, template<typename ELEM> class CONT = std::vector >
class Stack
{
private:
CONT elems;
public:
void push(T const&);
void pop();
T top() const;
bool empty() const
{
return elems.empty();
}
int32_t getElemsSize() const
{
return elems.size();
}
};
上面示例需要注意两点
template <typename T, template<typename ELEM> class CONT = std::vector >
必须使用class,CONT是为了定义一个类,只能使用class- 上面的示例无法使用,因为
std::vector
和模板的模板参数CONT不匹配,这里需要补充缺省值内存分配器allocator
;
最终示例:
/*
* @brief: class complates
* @complie: g++ -g *.cc -o d -std=c++11
* @autor: your name
* @date: 2023/08/27
*/
#include <iostream>
#include <vector>
#include <deque>
template <typename T, template <typename ELEM, typename ALLOC = std::allocator<ELEM> > class CONT = std::vector>
class Stack
{
private:
CONT<T> elems;
public:
void push(T const&);
void pop();
T top() const;
bool empty() const
{
return elems.empty();
}
int32_t getElemsSize() const
{
return elems.size();
}
};
template <typename T, template <typename, typename> class CONT>
void Stack<T, CONT>::push(T const& elem)
{
elems.push_back(elem);
}
template <typename T, template <typename, typename> class CONT>
void Stack<T, CONT>::pop()
{
if(elems.empty())
{
throw std::out_of_range("empty stack");
}
elems.pop_back();
}
template <typename T, template <typename, typename> class CONT>
T Stack<T, CONT>::top() const
{
if(elems.empty())
{
throw std::out_of_range("empty stack");
}
return elems.back();
}
int main(int argc, char* argv[])
{
//使用默认值
Stack<int> int_stack;
int_stack.push(10);
int_stack.push(20);
int_stack.push(30);
std::cout<<int_stack.top()<<std::endl;
//赋值类型
Stack<double, std::deque> double_stack;
double_stack.push(10.11);
double_stack.push(20.22);
double_stack.push(30.33);
std::cout<<double_stack.top()<<std::endl;
return 0;
}
3.特别说明
在template <typename T, template <typename ELEM, typename ALLOC = std::allocator<ELEM> > class CONT = std::vector>
中第二个参数其实本身就是一个类模板,可以将其摘出来进行进一步的分析;
#include <iostream>
#include <vector>
#include <deque>
template <typename ELEM, typename ALLOC = std::allocator<ELEM> >
class CONT
{
public:
void printInfo()
{
std::cout<<"print info"<<std::endl;
}
};
int main(int argc, char* argv[])
{
CONT<int> C;
C.printInfo();
return 0;
}
在template <typename T, template <typename ELEM, typename ALLOC = std::allocator<ELEM> > class CONT = std::vector>
中,CONT接受的类型其实就是T,当然换成其他的类型也可以;