C++ Templates

【C++ Templates(11)】深入模板基础

2018-05-10  本文已影响180人  downdemo

参数化声明

// details/definitions1.hpp

template<typename T> // a namespace scope class template
class Data {
public:
    static constexpr bool copyable = true;
    ...
};
template<typename T> // a namespace scope function template
void log (T x) {
   ...
}

template<typename T> // a namespace scope variable template (since C++14)
T zero = 0;

template<typename T> // a namespace scope variable template (since C++14)
bool dataCopyable = Data<T>::copyable;

template<typename T> // a namespace scope alias template
using DataList = Data<T*>;
// details/definitions2.hpp

class Collection {
public:
    template<typename T>        // an in-class member class template definition
    class Node {
        ...
    };

    template<typename T>        // an in-class (and therefore implicitly inline)
    T* alloc() {                // member function template definition
        ...
    }

    template<typename T>        // a member variable template (since C++14)
    static T zero = 0;
    template<typename T>        // a member alias template
    using NodePtr = Node<T>*;
};
// details/definitions3.hpp


template<typename T>            // a namespace scope class template
class List {
public:
    List() = default;           // because a template constructor is defined

    template<typename U>        // another member class template,
    class Handle;              // without its definition

    template<typename U>        // a member function template
    List (List<U> const&);     // (constructor)

    template<typename U>        // a member variable template (since C++14)
    static U zero;
};

template<typename T>            // out-of-class member class template definition
    template<typename U>
class List<T>::Handle {
    ...
};

template<typename T>            // out-of-class member function template definition
    template<typename T2>
List<T>::List (List<T2> const& b)
{
    ...
}

template<typename T>           // out-of-class static data member template definition
    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 (Stack<T> const&, int number = 10);

template <typename T>
void fill (Array<T>&, T const& = T{}); // C++11前要写为T()
class Value {
public:
    explicit Value(int);  // no default constructor
};

void init (Array<Value>& array)
{
    Value zero(0);
    fill(array, zero);   // OK: default constructor not used
    fill(array);         // ERROR: undefined default constructor for Value is used
}
template<int I>
class CupBoard
{
    class Shelf;                // ordinary class in class template
    void open();                // ordinary function in class template
    enum Wood : unsigned char;  // ordinary enumeration type in class template
    static double totalWeight;  // ordinary static data member in class template
};

template<int I>         // definition of ordinary class in class template
class CupBoard<I>::Shelf {
    ...
};

template<int I>         // definition of ordinary function in class template
void CupBoard<I>::open()
{
    ...
}

template<int I>         // definition of ordinary enumeration type class in class template
enum CupBoard<I>::Wood {
    Maple, Cherry, Oak
};

template<int I>         // definition of ordinary static member in class template
double CupBoard<I>::totalWeight = 0.0;
template<int I>
class CupBoard
    ...
    inline static double totalWeight = 0.0;
};

虚成员函数

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

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

模板的链接(Linkage of Template)

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

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>     // refers to the same entity as a declaration of the
void external();         // same name (and scope) in another file

template<typename T>     // unrelated to a template with the same name in
static void internal();  // another file

template<typename T>     // redeclaration of the previous declaration
static void internal();

namespace {
    template<typename>     // also unrelated to a template with the same name
    void otherInternal();  // in another file, even one that similarly appears
}                        // in an unnamed namespace

namespace {
    template<typename>     // redeclaration of the previous template declaration
    void otherInternal();
}

struct {
    template<typename T> void f(T) {}  // no linkage: cannot be redeclared
} x;

基本模板(Primary Templates)

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>
class X; // X<> is parameterized by a type and an integer
template<typename T,             // the first parameter is used
    T Root,                 // in the declaration of the second one and
    template<T> class Buf>  // in the declaration of the third one
class Structure;

非类型参数

template <typename T, // 类型参数
    typename T::Allocator* Allocator> // 非类型参数
class List;
template<int buf[5]> class Lexer;         // buf is really an int*
template<int* buf> class Lexer;           // OK: this is a redeclaration

template<int fun()> struct FuncWrap;      // fun really has pointer to function type
template<int (*)()> struct FuncWrap;      // OK: this is a redeclaration
template <int const length> class Buffer; // const被忽略
template <int length> class Buffer; // 和上面的声明等价
template<int& Counter>
struct LocalIncrement {
    LocalIncrement() { Counter = Counter + 1; }   //OK: reference to an integer
    ~LocalIncrement() { Counter = Counter - 1; }
};

模板的模板参数

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);
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;  // ERROR: a template template parameter cannot be used here
    ...
};
template <template <typename, // 省略T
    typename = MyAllocator> class Container>
class Adaptation {
    Container<int> storage; // Container<int, MyAllocator>
    ...
};

模板参数包(Template Parameter Pack)

template<typename... Types>   // declares a template parameter pack named Types
class Tuple;
using IntTuple = Tuple<int>;              // OK: one template argument
using IntCharTuple = Tuple<int, char>;    // OK: two template arguments
using IntTriple = Tuple<int, int, int>;   // OK: three template arguments
using EmptyTuple = Tuple<>;               // OK: zero template arguments
template<typename T, unsigned... Dimensions>
class MultiArray;       // OK: declares a nontype template parameter pack

using TransformMatrix = MultiArray<double, 3, 3>;   // OK: 3x3 matrix

template<typename T, template<typename,typename>... Containers>
void testContainers();  // OK: declares a template template parameter pack
template<typename... Types, typename Last>
class LastType;  // ERROR: template parameter pack is not the last template parameter

template<typename... TestTypes, typename T>
void runTests(T value);  // OK: template parameter pack is followed
                         //     by a deducible template parameter
template<unsigned...> struct Tensor;
template<unsigned... Dims1, unsigned... Dims2>
    auto compose(Tensor<Dims1...>, Tensor<Dims2...>);
                         // OK: the tensor dimensions can be deduced
template<typename...> Typelist;
template<typename X, typename Y> struct Zip;
template<typename... Xs, typename... Ys>
    struct Zip<Typelist<Xs...>, Typelist<Ys...>>;
          // OK: partial specialization uses deduction to determine
          //     theXs and Ys substitutions
template<typename... Ts, Ts... vals> struct StaticValues {};
    // ERROR: Ts cannot be expanded in its own parameter list
template<typename... Ts> struct ArgList {
    template<Ts... vals> struct Vals {};
};
ArgList<int, char, char>::Vals<3, 'x', 'y'> tada;

默认模板实参

template <typename T, typename Allocator = allocator<T>>
class List;
template <typename T1, typename T2, typename T3,
    typename T4 = char, typename T5 = char>
class Quintupe; // 正确

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

template <typename T1 = char, typename T2, typename T3,
    typename T4, typename T5>
class Quintupe; // 错误:T2没有缺省值
template<typename R = void, typename T>
R* addressof(T& value);  // OK: if not explicitly specified, R will be void
template <typename T = void>
class Value;

template <typename T = void> // 错误:重复定义默认实参
class Value;
// 局部特化
template<typename T>
class C;
...
template<typename T = int>
class C<T*>;                                        // ERROR

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

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

template<typename T = int> T X<T>::f() {          // ERROR
    ...
}

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

// 友元函数模板声明,除非它是一个定义且在同一编译单元的其他地方未出现过
struct S {
template<typename = void> friend void f();    // ERROR: not a definition
    template<typename = void> friend void g() {   // OK so far
    }
};
template<typename> void g();  // ERROR: g() was given a default template argument
                              // when defined; no other declaration may exist here

模板实参

函数模板实参

// details/max.cpp

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 (SrcT const& 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(typename T::X const*);
template <typename T> RT2 test(...);
typedef char RT1;
typedef struct { char a[2]; } RT2;
template <typename T> RT1 test(typename T::X const*);
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; // 指向成员的指针常量

template <typename T>
void templ_func();

C<long, X{}>* c7; // X先通过constexpr转换函数转为int,然后由int转为long
template<char const* 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 expects one parameter
class Rel {
    ...
};

Rel<int, double, std::list> rel;  // ERROR before C++17: std::list has more than one template parameter
#include <memory>
template <typename T1,
    typename T2,
    template<typename T,
        typename = std::allocator<T>> class Container>
class Relation {
public:
    ...
private:
    Container<T1> dom1;
    Container<T2> dom2;
};
#include <list>

template<typename T1, typename T2,
    template<typename... > class Cont>  // Cont expects any number of type parameters
class Rel {
    ...
};

Rel<int, double, std::list> rel;  // OK: std::list has two template parameters
                                  //     but can be used with one argument
#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; //two type parameters
AlmostAnyTmpl<std::map> withMap;       // four type parameters
AlmostAnyTmpl<std::array> withArray;   // ERROR: a template type parameter pack
                                       // doesn't match a nontype template parameter

实参的等价性

template <typename T, int I>
class Mix;

typedef int Int;

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

template<int M, int N> void f(I<M+N>);  // #1
template<int N, int M> void f(I<N+M>);  // #2

template<int M, int N> void f(I<N+M>);  // #3 ERROR

可变参数模板(Varaidic Template)

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

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

int a1[Tuple<int>::length];              // array of one integer
int a3[Tuple<short, int, long>::length]; // array of three integers

包扩展(Pack Expansion)

template<typename... Types>
class MyTuple : public Tuple<Types...> {
    // extra operations provided only for MyTuple
};

MyTuple<int, float> t2;  // inherits from Tuple<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; // Inherits from 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... {    // base class pack expansion
    double x, y, z;
public:
    Point() : Mixins()... { }         // base class initializer pack expansion

    template<typename Visitor>
    void visitMixins(Visitor visitor) {
        visitor(static_cast<Mixins&>(*this)...); // call argument pack expansion
    }
};

struct Color { char red, green, blue; };
struct Label { std::string name; };
Point<Color, Label> p;             // inherits from both Color and 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...
{
    double x, y, z;
public:
    //default constructor, visitor function, etc. elided*
    Point(Mixins... mixins)    // mixins is a function parameter pack
    : Mixins(mixins)... { }  //initialize each base with the supplied mixin value
};

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'); // calls print<std::string, char const*, int, char>
}
template<typename T> void c_style(int, T...);
template<typename... T> void pack(int, T...);

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

template<typename F, typename... Types>
void forwardCopy(F f, Types const&... values) {
    f(Types(values)...);
}
template<typename F, typename T1, typename T2, typename T3>
void forwardCopy(F f, T1 const& v1, T2 const& v2, T3 const& v3) {
    f(T1(v1), T2(v2), T3(v3));
}
template<typename... OuterTypes>
class Nested {
    template<typename... InnerTypes>
    void f(InnerTypes const&... innerValues) {
        g(OuterTypes(InnerTypes(innerValues)...)...);
    }
};
template<typename O1, typename O2>
class Nested {
    template<typename I1, typename I2, typename I3>
    void f(I1 const& iv1, I2 const& iv2, I3 const& iv3) {
        g(O1(I1(iv1), I2(iv2), I3(iv3)),
            O2(I1(iv1), I2(iv2), I3(iv3)),
            O3(I1(iv1), I2(iv2), I3(iv3)));
    }
};

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

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

折叠表达式(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) // for a right fold of the operator (called a binary right fold)
(value op ... op pack) // for a left fold (called a binary left fold)
template<typename... T> bool g() {
    return and_all(trait<T>()...);
}
template<typename... T> bool g() {
    return (trait<T>() && ... && true);
}
(pack op ... ) // unary right fold
(... op pack) // unary left fold
struct BooleanSymbol {
    ...
};

BooleanSymbol operator||(BooleanSymbol, BooleanSymbol);

template<typename... BTs>
void symbolic(BTs... ps) {
    BooleanSymbol result = (ps || ...);
    ...
}

友元

类模板的友元类

template <typename T>
class Node;

template <typename T>
class Tree {
    friend class Node<T>;
    ...
};
template <typename T>
class Tree {
    friend class Factory; // 正确,即使这是首次声明Factory
    friend class Node<T>; // 错误:未声明过Node
};
template<typename T>
class Stack {
public:
    ...
    // assign stack of elements of type T2
    template<typename T2>
    Stack<T>& operator= (Stack<T2> const&);
    // to get access to private members of Stack<T2> for any type T2:
    template<typename> friend class Stack;
    ...
};
template<typename T>
class Wrap {
    friend T; // valid for any type T, but ignored if T is not class type
    ...
};

类模板的友元函数

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

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

template <typename T>
void multiply(T);

class Comrades {
    friend void multiply(int) {} // 定义了一个新函数::multiply(int)
    friend void ::multiply(void*); // 引用上面的普通函数
    friend void ::multiply(int); // 引用一个模板实例
    friend void ::multiply<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 Creator {
    friend void appear() { // 定义一个新函数::appear()
        ... // 只有当Creator实例化后该函数才存在
    }
};
Creator<void> miracle; // ::appear()此时被生成
Creator<double> oops; // 错误:第二次生成::appear()
template<typename T>
class Creator {
    friend void feed(Creator<T>) {  //every T instantiates a different function ::feed()
        ...
    }
};

int main()
{
    Creator<void> one;
    feed(one);                     // instantiates ::feed(Creator<void>)
    Creator<double> two;
    feed(two);                     // instantiates ::feed(Creator<double>)
}

友元模板

class Manager {
    template <typename T>
        friend class Task;

    template <typename T>
        friend void Schedule<T>::dispatch(Task<T>*);

    template <typename T>
        friend int ticket() {
            return ++Manager::counter;
        }
    static int counter;
};
上一篇 下一篇

猜你喜欢

热点阅读