[c++][template]模板基础知识

  1. typename
template <typename T>
class MyClass {
typename T::SubType * ptr;
};

如果不使用typename,SubType会被认为是一个静态成员,T::SubType就会被解释成两个变量的乘积。

typename的典型应用: STL容器的iterator

// basics/printcoll.hpp

#include <iostream>

// print elements of an STL container
template <typename T>
void printcoll (T const& coll)
{
typename T::const_iterator pos;  // iterator to iterate over coll
typename T::const_iterator end(coll.end());  // end position

for (pos=coll.begin(); pos!=end; ++pos) {
std::cout << *pos << ' ';
}
std::cout << std::endl;
}

class stlcontainer {
typedef …   iterator;        // iterator for read/write access
typedef …   const_iterator;  // iterator for read access
};
  1. this->

下面的例子中foo()调用exit(),它不会调用父类Base的exit(),而是会调用外部定义的exit()。如果要调用父类的exit()就需要加上this->或者Base::

template <typename T>
class Base {
public:
void exit();
};

template <typename T>
class Derived : Base<T> {
public:
void foo() {
exit();   // calls external exit() or error
}
};
  1. 成员模板(Member Templates)

我们有这样的需求:把两个不同模板类型的类相互赋值。

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 types

这里我们就需要使用成员模板

// basics/stack5decl.hpp

template <typename T>
class Stack {
private:
std::deque<T> elems;   // elements

public:
void push(T const&);   // push element
void pop();            // pop element
T top() const;         // return top element
bool empty() const {   // return whether the stack is empty
return elems.empty();
}

// assign stack of elements of type T2
template <typename T2>
Stack<T>& operator= (Stack<T2> const&);
};

operator=的实现:

// basics/stack5assign.hpp

template <typename T>
template <typename T2>
Stack<T>& Stack<T>::operator= (Stack<T2> const& op2)
{
if ((void*)this == (void*)&op2) {    // assignment to itself?
return *this;
}

Stack<T2> tmp(op2);             // create a copy of the assigned stack

elems.clear();                  // remove existing elements
while (!tmp.empty()) {          // copy all elements
elems.push_front(tmp.top());
tmp.pop();
}
return *this;
}
  1. 模板的模板参数(Template Template Parameters)

当我们要指定一个Stack模板类型时,要这样写:

Stack > vStack; // integer stack that uses a vector

这样有些繁琐int出现了两次,我们希望的是:

Stack<int,std::vector> vStack;  // integer stack that uses a vector
此时就要用到模板的模板参数
// basics/stack7decl.hpp

template <typename T,
template <typename ELEM> class CONT = std::deque >
class Stack {
private:
CONT<T> elems;         // elements

public:
void push(T const&);   // push element
void pop();            // pop element
T top() const;         // return top element
bool empty() const {   // return whether the stack is empty
return elems.empty();
}
};

这里有几点需要注意的是:

1)template class CONT = std::deque中的class不能换成typename

2)模板的模板参数不能用于函数模板

3)根据上述的默认值std::deque会得到一个编译错误:

error C3201: the template parameter list for class template 'std::deque' does not match the template parameter list for template parameter 'CONT'

发生这个错误的原因是:

std::deque除了ELEM这个模板参数之外,还有另一个allocator的参数:typename ALLOC = std::allocator

在模板编译的时候要求模板定义的参数CONT与模板的实参完全一致,我们需要将allocator参数加上:

template <typename T,
template <typename ELEM,
typename ALLOC = std::allocator<ELEM> >
class CONT = std::deque>
class Stack {
private:
CONT<T> elems;         // elements
};

5. 初始化为0(Zero Initialization)

这里要解决的问题是如何将模板类型的变量初始化

template <typename T>
void foo()
{
T x = T();    // x is zero (or false)ifT is a built-in type
}

template <typename T>
class MyClass {
private:
T x;
public:
MyClass() : x() {  // ensures that x is initialized even for built-in types
}
};

上面分别介绍了对函数内的局部变量和类变量的初始化。

6. 字符串作为函数模板的实参

// basics/max5.cpp

#include <string>

// note: reference parameters
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}

int main()
{
std::string s;

::max("apple","peach");   // OK: same type
::max("apple","tomato");  // ERROR: different types
::max("apple",s);         // ERROR: different types
}

这里发生编译错误的原因是"apple”和"tomato”的类型分别是char const[6]和char const[7]。

最好的解决方法就是为字符串重载max()

7. 模板源代码组织

(1)包含模型

把模板函数和模板类的实现放在头文件中,这个方法是相对来说最简单,最推荐的方法。

(2)显式实例化

手工对需要的模板类型进行实例化,而不依赖编译器。这种做法的好处就是可以把模板函数的声明和定义分开,并且可以精确控制模板实例的准确位置,坏处就是需要人工的跟踪每个需要实例化的实体,不适合用于大项目。

包含模型和显式实例化整合

image image

(3) 分离模型

分离模型就是通过使用export关键字来实现模板声明和定义的分离,很完美?不过它有一个非常重大的缺陷:

它会产生看不见的代码耦合(模板的声明和定义在不同文件中),当定义发生变化时,所有调用该模板函数的地方都需要重编译,而这些对一些编译工具来说是不可见的,比如Makefile。所以不推荐使用。

分离和包含模型的转换

// basics/myfirst4.hpp

#ifndef MYFIRST_HPP
#define MYFIRST_HPP

// use export if USE_EXPORT is defined
#if defined(USE_EXPORT)
#define EXPORT export
#else
#define EXPORT
#endif

// declaration of template
EXPORT
template <typename T>
void print_typeof (T const&);

// include definition if USE_EXPORT is not defined
#if !defined(USE_EXPORT)
#include "myfirst.cpp"
#endif

#endif // MYFIRST_HPP

// use separation model:
#define USE_EXPORT
#include "myfirst.hpp"

// use inclusion model:
#include "myfirst.hpp"

原文链接: https://www.cnblogs.com/xuczhang/archive/2010/06/11/1756088.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/11715

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 上午10:25
下一篇 2023年2月7日 上午10:27

相关推荐