本篇介绍
本篇摘录自<<C templates>>,记录其中部分内容。
Variadic Templates
操作可变参数
代码语言:javascript复制template <typename T>
void func(T arg) {
std::cout<< arg << std::endl;
}
template <typename T, typename ... Types>
void func(T firstArg, Types... args) {
func(firstArg);
func(args...);
}
使用sizeof...(args)即可获取到变量个数。
在c 17上可以按照如下方式操作可变入参:
代码语言:javascript复制template <typename... T>
auto sum(T... s) {
return (... s); // ((s1 s2) s3)
}
具体格式如下:
image.png
std::enable_if
利用SFINE性质,也就是只要可以匹配成功,即使某些场景匹配失败也不是错误。
代码语言:javascript复制template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
using 在模版中的使用
using 有给类型重命名的作用,也有继承父类所有构造函数的作用,比如:
代码语言:javascript复制struct Base {
int val;
Base() { val = 0;}
Base(int m):val(m) {
}
};
struct Derived : public Base {
using Base::Base;
};
通过using 就可以一下子使用到父类的所有构造函数。
也可以通过模版支持获取所有类的操作符重载方法:
代码语言:javascript复制class Customer
{
private:
std::string name;
public:
Customer(std::string const& n) : name(n) { }
std::string getName() const { return name; }
};
struct CustomerEq {
bool operator() (Customer const& c1, Customer const& c2) const {
return c1.getName() == c2.getName();
}
};
struct CustomerHash {
std::size_t operator() (Customer const& c) const {
return std::hash<std::string>()(c.getName());
}
};
template<typename... Bases>
struct Overloader : Bases...
{
using Bases::operator()...;
};
using CustomerOP = Overloader<CustomerHash,CustomerEq>;
std::unordered_set<Customer,CustomerOP,CustomerOP> col;
typename
在模版使用过程中,typename 和class 是等同的,不过typename还有一层含义,就是修饰的参数一定是类型。
代码语言:javascript复制 template<typename T>
class MyClass {
public: ...
void foo() {
typename T::SubType* ptr;
} };
这儿的 T::SubType 是类型。
模版友元
如果希望支持模版不同特化之间可以访问私有数据,那么就可以设置模版特化是友元的。
代码语言:javascript复制template <typename T>
class Stack {
template <typename> friend class Stack;
};
变量模版
可以用变量来表示类模版的成员值:
代码语言:javascript复制 namespace std {
template<typename T> constexpr bool is_const_v = is_const<T>::value;
}
这样通过is_const_v<T> 就可以表示 is_const<T>::value
模版模版参数
如果模版参数中的类型本身也是一个模版,比如还是Stack, Stack<int, std::vector<int>> 可以看到第一个模版参数是int,第二个模版参数还是一个int,这时候就是模版的模版参数了,要声明这种场景,方法如下:
代码语言:javascript复制template<typename T,
template<typename Elem> class Cont = std::deque>
在模版里再写一下 template<typename Elem>,就表明第二个参数也是模版。 这时候完整的Stack 如下:
代码语言:javascript复制#include <deque>
#include <cassert>
#include <memory>
template<typename T,
template<typename Elem,
typename = std::allocator<Elem>>
class Cont = std::deque>
class Stack {
private:
Cont<T> elems;
public:
void push(T const&);
void pop();
T const& top() const;
bool empty() const {
return elems.empty();
}
// assign stack of elements of type T2 template<typename T2,
template<typename Elem2,
typename = std::allocator<Elem2>
>class Cont2>
Stack<T,Cont>& operator= (Stack<T2,Cont2> const&);
// to get access to private members of any Stack with elements of type T2: template<typename, template<typename, typename>class> friend class Stack;
};
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
}
template<typename T, template<typename,typename> class Cont>
void Stack<T,Cont>::pop ()
{
assert(!elems.empty());
elems.pop_back();
// remove last element
}
template<typename T, template<typename,typename> class Cont>
T const& Stack<T,Cont>::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}
template<typename T, template<typename,typename> class Cont>
template<typename T2, template<typename,typename> class Cont2>
Stack<T,Cont>&
Stack<T,Cont>::operator= (Stack<T2,Cont2> const& op2)
{
elems.clear();
elems.insert(elems.begin(),
op2.elems.begin(),
op2.elems.end());
return *this;
// remove existing elements // insert at the beginning
// all elements from op2
}