template<typename T, int N, int M> boolless(T(&a)[N], T(&b)[M]) { for (int i = 0; i < N && i < M; ++i) { if (a[i] < b[i]) returntrue; if (b[i] < a[i]) returnfalse; } return N < M; }
这里,当使用
1 2 3
int x[] = {1, 2, 3}; int y[] = {1, 2, 3, 4, 5}; std::cout << less(x, y) << '\n';
less<>() 中的 T 被实例化为 int,N 被实例化为 3,M 被实例化为 5。
你也可以将此模板运用于字符串常量:
1
std::cout << less("ab", "abc") << '\n';
在这个例子中,less<>() 中的 T 被实例化为 char const,N 被实例化为 3,M 被实例化为 4。
当你只想为字符串常量(或者其他 char 数组)提供专门函数模板,你可以这么做。
1 2 3 4 5 6 7 8 9
template<int N, int M> boolless(charconst(&a)[N], charconst(&b)[M]) { for (int i = 0; i < N && i < M; ++i) { if (a[i] < b[i]) returntrue; if (b[i] < a[i]) returnfalse; } return N < M; }
Stack<int> intStack1, intStack2; // stacks for ints Stack<float> floatStack; // stack for floats ... intStack1 = intStack2; // OK: stacks have same type floatStack = intStack1; // ERROR:stacks have different type
默认赋值运算符需要等式两边的类型相同,因此如果两个 stack 的类型不同的话,这一条件不满足。
通过为模板定义一个赋值运算符,你就可以对两个不同类型的 stack 互相赋值。你可以如下定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
template <typename T> classStack { private: std::deque<T> elems; // elements
public: voidpush(T const&); // push element voidpop(); // pop element T const& top()const; // return top element boolempty()const{ // return whether the stack is empty return elems.empty(); }
// assign stack of elements of type T2 template <typename T2> Stack& operator= (Stack<T2> const&); };
template<typename T> classStack { private: std::deque<T> elems; // elements
public: voidpush(T const&); // push element voidpop(); // pop element T const& top()const; // return top element boolempty()const{ // return whether the stack is empty return elems.empty(); }
// assign stack of elements of type T2 template<typename T2> Stack& operator= (Stack<T2> const&); // to get access to private members of \TStack<T2> for any type T2: template<typename> friendclassStack; };
正如你所见,因为模板参数的名称没有被使用,所以可以省略:
1
template<typename> friendclassStack;
这样,下面的模板赋值运算符的实现是有效的:
1 2 3 4 5 6 7 8 9 10
template<typename T> template<typename T2> Stack<T>& Stack<T>::operator= (Stack<T2> const& op2) { elems.clear(); // remove existing elements elems.insert(elems.begin(), // insert at the beginning op2.elems.begin(), // all elements from op2 op2.elems.end()); return *this; }
无论你采用哪种实现方式,通过这个成员模板,你可以将 int 类型的 stack 赋值给 float 类型的 stack:
1 2 3 4 5
从 Stack<int> intStack; // stack for ints Stack<float> floatStack; // stack for floats ... floatStack = intStack; // OK: stacks have different types, // but int converts to float
template<typename T, typename Cont = std::deque<T>> class Stack { private: Cont elems; // elements
public: voidpush(T const&); // push element voidpop(); // pop element T const& top()const; // return top element boolempty()const// return whether the stack is empty { return elems.empty(); }
// assign stack of elements of type T2 template<typename T2, typename Cont2> Stack& operator= (Stack<T2,Cont2> const&); // to get access to private members of Stack<T2> for any type T2: template<typename, typename> friendclassStack; };
模板赋值运算符的实现像下面这样:
1 2 3 4 5 6 7 8 9 10 11
template<typename T, typename Cont> template<typename T2, typename Cont2> Stack<T,Cont>& Stack<T,Cont>::operator= (Stack<T2,Cont2> const& op2) { elems.clear(); // remove existing elements elems.insert(elems.begin(), // insert at the beginning op2.elems.begin(), // all elements from op2 op2.elems.end()); return *this; }
// stack for ints using a vector as an internal container Stack<int, std::vector<int>> vStack; ... vStack.push(42); vStack.push(7); std::cout << vStack.top() << '\n';
// boolstring.hpp classBoolString { private: std::string value; public: BoolString (std::string const& s) : value(s) {} template<typename T = std::string> T get()const// get value (converted to T) { return value; } };
1 2 3 4 5 6
// full specialization for BoolString::getValue<>() for bool template<> inlinebool BoolString::get<bool>() const { return value == "true" || value == "1" || value == "on"; }
template <typename T = longdouble> constexpr T pi = {3.1415926535897932385};
你可以使用默认的后者是其他的类型:
1 2
std::cout << pi<> << '\n'; // outputs a long double std::cout << pi<float> << '\n'; // outputs a float
但是,注意你必须使用尖括号,如果直接使用 pi 会产生错误:
1
std::cout << pi << '\n'; // ERROR
变量模板也可以被非类型参数实例化参数化,这也用于对初始化器的参数化。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include<iostream> #include<array>
template<int N> std::array<int, N> arr{}; // array with N elements, zero-initialized template<auto N> constexprdecltype(N) dval = N; // type of dval depends on passed value
intmain() { std::cout << dval<'c'> << '\n'; // N has value 'c' of type char arr<10>[0] = 42; // set first element of global arr for (std::size_t i = 0; i < arr<10>.size(); ++i) // uses values set in arr { std::cout << arr<10>[i] << '\n'; } }
public: voidpush(T const &); // push element voidpop(); // pop element T const &top()const; // return top element boolempty()const// return whether the stack is empty { return elems.empty(); } //... };
template<typename T, template<typename Elem, typename = std::allocator<Elem>> class Cont = std::deque> class Stack { private: Cont<T> elems; // elemenats
public: voidpush(T const&); // push element voidpop(); // pop element T const& top()const; // return top element boolempty()const{ // return whether the stack is empty return elems.empty(); }
// assign stack of elements ofatype 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> friendclassStack; };
template<typename T, template<typename,typename> classCont> void Stack<T,Cont>::pop () { assert(!elems.empty()); elems.pop_back(); // remove last element }
template<typename T, template<typename,typename> classCont> T const& Stack<T,Cont>::top () const { assert(!elems.empty()); return elems.back(); // return copy of last element }
template<typename T, template<typename,typename> classCont> template<typename T2, template<typename,typename> classCont2> Stack<T,Cont>& Stack<T,Cont>::operator= (Stack<T2,Cont2> const& op2) { elems.clear(); // remove existing elements elems.insert(elems.begin(), // insert at the beginning op2.elems.begin(), // all elements from op2 op2.elems.end()); return *this; }
// assign stack of different type and manipulate again fStack = iStack; fStack.push(4.4); std::cout << "fStack.top(): " << fStack.top() << '\n';
// stack for doubless using a vector as an internal container Stack<double, std::vector> vStack; vStack.push(5.5); vStack.push(6.6); std::cout << "vStack.top(): " << vStack.top() << '\n';