11 深入模板基础

2021-05-28  本文已影响0人  奇点创客

参数化声明

template<typename T> // 类模板
class Data {
 public:
    static constexpr bool copyable = true;
};

template<typename T> // 函数模板
void f(T x) {}

template<typename T> // 变量模板
T zero = 0;

template<typename T> // 变量模板
bool dataCopyable = Data<T>::copyable;

template<typename T> // 别名模板
using DataList = Data<T*>;
class Collection {
 public:
  template<typename T> // 类模板
  class Node {};

  template<typename T> // 函数模板,由于类内定义所以将隐式内联
  T* alloc() {}

  template<typename T> // 变量模板
  static T zero = 0;

  template<typename T> // 别名模板
  using NodePtr = Node<T>*;
};
template<int I>
class CupBoard
  ...
  inline static double totalWeight = 0.0;
};
template<typename T>
class List {
 public:
  List() = default;

  template<typename U>
  class Handle;

  template<typename U>
  List(const List<U>&);

  template<typename U>
  static U zero;
};

template<typename T>
  template<typename U>
class List<T>::Handle
{
  ...
};

template<typename T>
  template<typename U>
List<T>::List(const List<U>& b)
{
  ...
}

template<typename T>
  template<typename U>
U List<T>::zero = 0;
template<typename T>
union AllocChunk {
  T object;
  unsigned char bytes[sizeof(T)];
};
template<typename T>
void report_top(const Stack<T>&, int number = 10);

template<typename T>
void fill(Array<T>&, const T& = T{}); // C++11前写为T()

虚成员函数

template<typename T>
class Dynamic {
 public:
  virtual ~Dynamic(); // 正确:每个Dynamic<T>对应一个析构函数

  template<typename U>
  virtual void copy(const U&); // 错误:编译器不知道一个Dynamic<T>中copy()个数
};

模板的链接(Linkage of Template)

int C;
class C; // OK:两者名称在不同的空间

int X;
template<typename T>
class X; // 错误:名称冲突

struct S;
template<typename T>
class S; // 错误:名称冲突
extern "C++" template<typename T>
void normal(); // 默认方式,上面的链接规范可以省略不写

extern "C" template<typename T>
void invalid(); // 错误:不能使用C链接

extern "Java" template<typename T>
void javaLink(); // 非标准链接:某些编译器可能支持
template<typename T> // 与其他文件中同名的声明指向相同的实体
void external();

template<typename T> // 与其他文件中同名的模板无关
static void internal();

template<typename T> // 重复声明
static void internal();

namespace {
template<typename> // 与其他文件中同名的模板无关
void otherInternal();
} 

namespace {
template<typename> // 重复声明
void otherInternal();
}

struct {
  template<typename T>
  void f(T) {}  // 无链接:不能被重复声明
} x;

原始模板(Primary Template)

template<typename T> class Box;        // OK: primary template
template<typename T> class Box<T>;       // ERROR: does not specialize

template<typename T> void translate(T);    // OK: primary template
template<typename T> void translate<T>(T);   // ERROR: not allowed for functions

template<typename T> constexpr T zero = T{};   // OK: primary template
template<typename T> constexpr T zero<T> = T{};  // ERROR: does not specialize

模板参数

template<typename, int> // 省略T
class X;
template<typename T, T Root, template<T> class Buf>
class Structure;

非类型参数(Nontype Parameter)

template<typename T, // 类型参数
  typename T::Allocator* Allocator> // 非类型参数
class List;
template<int buf[5]> class Lexer;
template<int* buf> class Lexer; // OK:重复声明

template<int fun()> struct FuncWrap; 
template<int (*)()> struct FuncWrap; // OK:重复声明
template<const int const length> class Buffer; // const会被忽略
template<int& Counter>
struct LocalIncrement {
  LocalIncrement() { Counter = Counter + 1; }   // OK:一个指向int的引用
  ~LocalIncrement() { Counter = Counter - 1; }
};

模板的模板参数(Template Template Parameter)

template<template<typename X> class C> // OK
void f(C<int>* p);

template<template<typename X> struct C> // 错误:不能用struct
void f(C<int>* p);

template<template<typename X> union C> // 错误:不能用union
void f(C<int>* p);
template<template<typename X> typename C> // OK since C++17
void f(C<int>* p);
template<template<typename T,
  typename A = MyAllocator> class Container>
class Adaptation {
  Container<int> storage; // Container<int, MyAllocator>
  ...
};
template<template<typename T, T*> class Buf>  // OK
class Lexer {
  static T* storage;  // 错误:模板的模板参数不能用在此处
  ...
};
template<template<typename, // 省略T
  typename = MyAllocator> class Container>
class Adaptation {
  Container<int> storage; // Container<int, MyAllocator>
  ...
};

模板参数包(Template Parameter Pack)

template<typename... Types>
class Tuple;
using IntTuple = Tuple<int>;
using IntCharTuple = Tuple<int, char>;
using IntTriple = Tuple<int, int, int>;
using EmptyTuple = Tuple<>;
template<typename T, unsigned... Dimensions>
class MultiArray;

using TransformMatrix = MultiArray<double, 3, 3>;

template<typename T, template<typename,typename>... Containers>
void testContainers();
template<typename... Types, typename Last>
class LastType; // 错误:模板参数包必须为最后一个参数

template<typename... TestTypes, typename T>
void runTests(T value); // OK:跟在参数包后的T能被推断

template<unsigned...> struct Tensor;
template<unsigned... Dims1, unsigned... Dims2>
auto compose(Tensor<Dims1...>, Tensor<Dims2...>); // OK:Dims1和Dims2能被推断
template<typename...> Typelist;
template<typename X, typename Y> struct Zip;
template<typename... Xs, typename... Ys>
struct Zip<Typelist<Xs...>, Typelist<Ys...>>; // OK:偏特化用推断替代Xs和Ys
template<typename... Ts, Ts... vals> // 错误:Ts不能用于声明其他参数
struct StaticValues {};
template<typename... Ts>
struct ArgList {
  template<Ts... vals>
  struct Vals {};
};

ArgList<int, char, char>::Vals<3, 'x', 'y'> data;

默认模板实参

template<typename T, typename Allocator = allocator<T>>
class List;
template<typename T1, typename T2, typename T3,
  typename T4 = char, typename T5 = char>
class X; // OK

template<typename T1, typename T2, typename T3 = char,
  typename T4, typename T5>
class X; // 正确:T4和T5在前面已经有了默认值

template<typename T1 = char, typename T2, typename T3,
  typename T4, typename T5>
class X; // 错误:T2没有默认值
template<typename R = void, typename T>
R* addressof(T& value);
template<typename T = void>
class Value;

template<typename T = void> // 错误:重复定义默认实参
class Value;
// 偏特化
template<typename T>
class C;

template<typename T = int>
class C<T*>; // 错误

// 参数包
template<typename... Ts = int> // 错误
struct X;

// 类模板成员的类外定义
template<typename T>
struct X {
  T f();
};

template<typename T = int> // 错误
T X<T>::f() {}

// 友元类模板声明
struct S {
  template<typename = void> // 错误
  friend struct F;
};

// 友元函数模板的默认实参只能在定义中指定,同一编译单元不能出现声明
struct S {
  template<typename = void>
  friend void f(); // 错误:不是一个定义

  template<typename = void> 
  friend void g() {} // OK
};

template<typename>
void g(); // 错误:g()在定义中给出了默认实参,这里不能有其他声明

模板实参

函数模板实参

template<typename T>
T max(T a, T b)
{
  return a < b ? b : a;
}

int main()
{
  ::max<double>(1.0, -3.0); // 显式指定
  ::max(1.0, -3.0); // 隐式推断
  ::max<int>(1.0, 3.0); // 指定为int抑制推导
}
// DstT未出现在参数列表中,无法被推导
template<typename DstT, typename SrcT>
DstT implicit_cast(const SrcT& x)
{
  return x;
}

int main()
{
  double value = implicit_cast<double>(-1); // 只需指定一个参数
}
template<typename Func, typename T>
void apply(Func funcPtr, T x)
{
  funcPtr(x);
}

template<typename T> void single(T);

template<typename T> void multi(T);
template<typename T> void multi(T*);

int main()
{
  apply(&single<int>, 3); // OK
  apply(&multi<int>, 7); // 错误:没有单个multi<int>
}
template<typename T> RT1 test(const typename T::X*);
template<typename T> RT2 test(...);
using RT1 = char;
using RT2 = struct { char a[2]; };
template<typename T> RT1 test(const typename T::X*);
template<typename T> RT2 test(...);
// 在编译期判断给定类型T是否具有成员类型X
#define type_has_member_type_X(T) (sizeof(test<T>(0)) == 1)
template<int I>
void f(int (&) [24/(4-I]);

template<int I>
void f(int (&) [24/(4+I]);

int main()
{
  &f<4>; // 错误:替换后第一个除数为0,未使用SFINAE原则
}
template<int N>
int g() { return N; }

template<int* P>
int g() { return *p; }

int main()
{
  return g<1>(); // 1不能被绑定到int*,应用了SFINAE原则
}

类型实参

template<typename T>
class List {
  ...
};

typedef struct {
  double x, y, z;
} Point;

typedef enum { red, green, blue } *ColorPtr;

int main()
{
  struct Association {
    int* p;
    int* q;
  };
  List<Association*> error1; // 错误:不能是局部类型
  List<ColorPtr> error2; // 错误:不能是unnamed type
  List<Point> ok; // 正确:无名的type因typedef有了名称
}
template<typename T>
void clear(T p)
{
  *p = 0; // 要求运算符*可用于类型T
}

int main()
{
  int a;
  clear(a); // 错误:int不支持*
}

非类型实参

template<typename T, T nontype_param>
class C;

C<int, 33>* c1; // 整型

int a;
C<int*, &a>* c2; // 外部变量的地址

void f();
void f(int);
C<void(*)(int), f>* c3; // 匹配f(int),f前的&省略

template<typename T>
void templ_func();

C<void(), &templ_func<double>>* c4; // 函数模板实例同时也是函数

struct X {
    static bool b;
    int n;
    constexpr operator int() const { return 42; }
};

C<bool&, X::b>* c5; // 静态成员是可取的变量/函数名称

C<int X::*, &X::n>* c6; // 指向成员的指针常量

C<long, X{}>* c7; // X先通过constexpr转换函数转为int,然后由int转为long
template<const char* str>
class Message {};

extern char const hello[] = "Hello World!";
char const hello11[] = "Hello World!";

void foo()
{
  static char const hello17[] = "Hello World!";

  Message<hello> msg03;   // OK in all versions
  Message<hello11> msg11;   // OK since C++11
  Message<hello17> msg17;   // OK since C++17
}
template<typename T, T nontypeParam>
class C;

struct Base {
  int i;
} base;

struct Derived : public Base {
} derived;

C<Base*, &derived>* err1; // 错误:不允许派生类转基类
C<int&, base.i>* err2; // 错误:域运算符(.)后的变量不被看成变量
int a[10];
C<int*, &a[0]>* err3; // 错误:不能使用数组内某个元素的地址

模板的模板实参

#include <list>
  // declares in namespace std:
  // template<typename T, typename Allocator = allocator<T>>
  // class list;

template<typename T1, typename T2,
  template<typename> class Cont>  // Cont期望一个参数
class Rel {
  ...
};

Rel<int, double, std::list> rel;  // 错误(C++17前):std::list有超过一个模板参数
template<typename T1,
  typename T2,
  template<typename T,
    typename = std::allocator<T>> class Container>
class Rel {
  ...
};
template<typename T1, typename T2,
  template<typename... > class Cont>
class Rel {
  ...
};

Rel<int, double, std::list> rel;
#include <list>
#include <map>
  // declares in namespace std:
  //  template<typename Key, typename T,
  //       typename Compare = less<Key>,
  //       typename Allocator = allocator<pair<Key const, T>>>
  //  class map;
#include <array>
  // declares in namespace std:
  //  template<typename T, size_t N>
  //  class array;

template<template<typename... > class TT>
class AlmostAnyTmpl {};

AlmostAnyTmpl<std::vector> withVector; // 两个类型参数
AlmostAnyTmpl<std::map> withMap; // 四个类型参数
AlmostAnyTmpl<std::array> withArray; // 错误:一个参数包不能同时匹配类型和非类型参数

实参的等价性

template<typename T, int I>
class Mix;

using Int = int;

Mix<int, 3*3>* p1;
Mix<Int, 4+5>* p2; // p2和p1类型相同
template<int N> struct I {};

template<int X, int Y> void f(I<X+Y>);  // #1
template<int Y, int X> void f(I<Y+X>);  // #2
template<int X, int Y> void f(I<Y+X>);  // #3 ERROR

可变参数模板(Varaidic Template)

template<typename... Types>
class Tuple {
  // provides operations on the list of types in Types
};

int main()
{
  Tuple<> t0;
  Tuple<int> t1;
  Tuple<int, float> t2;
}
template<typename... Types>
class Tuple {
 public:
  static constexpr std::size_t length = sizeof...(Types);
};

int a1[Tuple<int>::length]; // int a1[1]
int a3[Tuple<short, int, long>::length]; // int a3[3]

包扩展(Pack Expansion)

template<typename... Types>
class MyTuple : public Tuple<Types...> { // 模板实参Types...就是一个包扩展
  // extra operations provided only for MyTuple
};

MyTuple<int, float> t2;  // 派生自Tuple<int, float>
// int、float替换给参数包Types,Types...包扩展后又得到int和float实参
template<typename T1, typename T2>
class MyTuple : public Tuple<T1, T2> {
  // extra operations provided only for MyTuple
};
template<typename T1, typename T2, typename T3>
class MyTuple : public Tuple<T1, T2, T3> {
  // extra operations provided only for MyTuple
};
template<typename... Types>
class PtrTuple : public Tuple<Types*...> {
  // extra operations provided only for PtrTuple
};

PtrTuple<int, float> t3; // 派生自Tuple<int*, float*>
template<typename T1, typename T2, typename T3>
class PtrTuple : public Tuple<T1*, T2*, T3*> {
  // extra operations provided only for PtrTuple
};

包扩展出现的位置

template<typename... Mixins>
class Point : public Mixins... { // 基类包扩展
 public:
  Point() : Mixins()... { } // 基类初始化列表包扩展

  template<typename Visitor>
  void visitMixins(Visitor visitor)
  {
    visitor(static_cast<Mixins&>(*this)...); // 调用实参包扩展
  }
 private:
  double x, y, z;
};

struct Color { char red, green, blue; };
struct Label { std::string name; };
Point<Color, Label> p; // 派生自Color和Label
template<typename... Ts>
struct Values {
  template<Ts... Vs>
  struct Holder {};
};

int i;
Values<char, int, int*>::Holder<'a', 17, &i> valueHolder;

函数参数包

template<typename... Mixins>
class Point : public Mixins... {
 public:
    Point(Mixins... mixins) // mixins是一个函数参数包
  : Mixins(mixins)... { }  // 用mixin值初始化每个基类
 private:
  double x, y, z;
};

struct Color { char red, green, blue; };
struct Label { std::string name; };
Point<Color, Label> p({0x7F, 0, 0x7F}, {"center"});
template<typename... Types>
void print(Types... values);

int main
{
  std::string welcome("Welcome to ");
  print(welcome, "C++", 2011, '\n'); // 调用print<std::string, const char*, int, char>
}
template<typename T> void c_style(int, T...); // T... 被看成 T, ...
template<typename... T> void pack(int, T...); // T...是函数参数包

多重嵌套包扩展(Multiple and Nested Pack Expansion)

template<typename F, typename... Types>
void forwardCopy(F f, const Types&... args)
{
  f(Types(args)...);
}
template<typename F, typename T1, typename T2, typename T3>
void forwardCopy(F f, const T1& v1, const T2& v2, const T3& v3)
{
  f(T1(v1), T2(v2), T3(v3));
}
template<typename... T>
class Nested {
  template<typename... U>
  void f(const U&... x)
  {
    g(T(U(x)...)...);
  }
};
template<typename T1, typename T2>
class Nested {
  template<typename U1, typename U2, typename U3>
  void f(const U1& x1, const U2& x2, const U3& x3)
  {
    g(T1(U1(x1), U2(x2), U3(x3)), T2(U1(x1), U2(x2), U3(x3)));
  }
};

零长包扩展(Zero-Length Pack Expansion)

template<>
class Point : {
  Point() : {}
};
template<typename T, typename... Types>
void g(Types... args)
{
  T x(args...);
}

折叠表达式(Fold Expression)

bool and_all() { return true; }

template<typename T>
bool and_all(T cond)
{
  return cond;
}

template<typename T, typename... Ts>
bool and_all(T cond, Ts... conds)
{
  return cond && and_all(conds...);
}
(pack op ... op value) // 二元右折叠
(value op ... op pack) // 二元左折叠
template<typename... T>
bool g()
{
  return and_all(trait<T>()...);
}
template<typename... T>
bool g()
{
  return (trait<T>() && ... && true);
}
(pack op ...) // 一元右折叠
(... op pack) // 一元左折叠
struct X {
  ...
};

X operator||(X, X);

template<typename... T>
void f(T... args)
{
  X value = (args || ...);
  ...
}

友元类

template<typename T>
class Node;

template<typename T>
class Tree {
  friend class Node<T>; // 类模板Node必须在此前被声明并可见
  friend class X; // OK:即使其他地方没有声明此类
};
template<typename T>
class Stack {
 public:
  template<typename T2>
  Stack<T>& operator=(const Stack<U>&);
  // to get access to private members of Stack<U> for any type U:
  template<typename>
  friend class Stack;
};
template<typename T>
class Wrap {
  friend T; // 对任意类型T有效,但如果T不是类类型则被忽略
};

友元函数

template<typename T1, typename T2>
void f(T1, T2);

class Mixer {
  friend void f<>(int&, int&); // T1 = int&, T2 = int&
  friend void f<int, int>(int, int); // T1 = int, T2 = int
  friend void f<char>(char, int); // T1 = char, T2 = int
  friend void f<>(long, long) { ... } // 错误:不能在此定义
};
void f(void*); // 普通函数

template<typename T>
void f(T);

class X {
  friend void f(int) {} // 定义了一个新函数::f(int)
  friend void ::f(void*); // 引用上面的普通函数
  friend void ::f(int); // 引用一个模板实例
  friend void ::f<double*>(double*); // 受限名称可以带尖括号,但模板在此必须可见
  friend void ::error() {} // 错误:受限的友元不能是定义式
};
template<typename T>
class Node {
  Node<T>* allocate();
};

template<typename T>
class List {
  friend Node<T>* Node<T>::allocate();
};
template<typename T>
class X {
  friend void f() {} // 定义一个新函数::f(),X实例化后该函数才存在
};

int main()
{
  X<void> miracle; // ::f()此时被生成
  X<double> oops; // 错误:第二次生成::f()
}
template<typename T>
class X {
  friend void f();
};

void f() {}

int main()
{
  X<void> miracle; // OK
  X<double> oops; // OK
}
template<typename T>
class X {
  friend void f(X<T>) {}  // 每个T实例化一个不同的函数::f()
};

int main()
{
  X<void> a;
  f(a); // 实例化::f(X<void>)
  X<double> b;
  f(b); // 实例化::f(X<double>)
  X<void> c;
  f(c); // 已实例化过::f(X<void>),直接调用
}

友元模板

class X {
  template<typename T> friend class A;

  template<typename T>
  friend void B<T>::g(A<T>*);

  template<typename T>
  friend int f()
  {
    return ++X::n;
  }

  static int n;
};
上一篇下一篇

猜你喜欢

热点阅读