C++template 显示实例化

显示实例化
      包含模型能够确保所有需要的模板都已经实例化。这是因为:当需要进行实例化的时候,C++编译系统会自动产生对应的实例化体。另外,C++标准还提供了一种手工实例化模板的机制:显示实例化指示符(explicit instantiation directive)。
   1 显示实例化的例子
    为了说明手工实例化,让我们回顾前面那个导致链接器错误的例子。在此,为了避免这个链接其错误,我们可以通过给程序添加下面的文件:
    myfirstinst.cpp
    #include "myfirst.cpp"
    
    //基于类型double显示实例化print_typeof()
    template void print_typeof(double const &);
    显示实例化指示符由关键字template和紧接其后的我们所需要实例化的实体(可以是类、函数、成员函数等)的声明组成,而且, 该声明是一个已经用实参完全替换参数之后的声明。在我们的例子中,我们针对的是一个普通函数,但该指示符也适用于成员函数    和静态数据成员。避如:
    //基于int显式实例化MyClass<>的构造函数
    template MyClass::MyClass();
    //基于int显式实例化函数模板max()
    template int const& max(int const &, int const &);
    你还可以显式实例化类模板,这样就可以同时实例化它的所有类成员,但有一点需要注意:对于这些在前面已经实例化过的成员,就不能再次对它们进行实例化:
    //基于int显式实例化类Stack<>
    template class Stack
    
    //基于string显式实例化Stack<>的某些成员函数
    template Stack::Stack();
    template void Stack::push(std::string const &);
    template std::string Stack::top() const;
    
    //错误:对于前面已经显式实例化过的成员函数,不能再次对它进行显式实例化
    template Stack::Stack();
    对于每个不同实体,在一个程序中最多只能有一个显式实例化体,换句话,你可以同时显式实例化print_typeof和print_typeof,但在同一个程序中每个指示符都只能够出现一次。如果不遵循这条规则,通常都会导致链接错误,链接器会报告:发现了实例化实体的重复定义。
     人工实例化有一个显著的缺点:我们必须仔细跟踪每个需要实例化的实体。对于大项目而言,这种跟踪很快就会带来巨大负担;因此,我们不建议使用这种方法。事实上,我们曾经在几个大项目刚开始时就低估了这种负担,而等到代码快要完成的时候,我们就为使用人工实例化而后悔不已。
    然而,显式实例化还是有它自身的一些优点的,实例化可以在需要的时候才进行。显然,我们因此避免包含庞大头文件的开销,更可以把模板定义的源文件封装起来;但封装之后,客户端程序就不能基于其他类型来进行额外的实例化了。另外,对于某些程序,精确控制模板实例的准确位置也是很有用的,显式实例化就可以做到这一点;而如果使用自动实例化的话,这种精确位置控制是不可能的(细节请参见第10章)。
 2 整合包含模型和显式实例化
    为了让程序员能够根据实际情况,自由地选择包含模型或者显式实例化,我们可以把模板的定义和模板的声明放在两个不同的文件中。通常的做法是使用头文件来表示两个文件(头文件大多是那些希望被#include、具有特定扩展名的文件);通常而言,遵守这种文件分 开约定是明智的(因此,我们最前面例子中的myfirst.cpp文件,现在将命名为myfirstdef.h,由预处理器来检测这些被插入的代码)。下面所示的基于Stack<>类模板阐明了这一点。
    

//stack.h
#ifndef STACK_H
#define STACK_H

#include 

template 
class Stack {
private:
    std::vector elems;
public:
    Stack();
    void push(T const &elem);
    void pop();
    T top() const;
};

#endif // STACK_H
//stackdef.h
#ifndef STACKDEF_H
#define STACKDEF_H

#include "stack.h"
#include 
#include 

template 
Stack::Stack()
{
    elems.clear();

}

template 
void Stack::push(T const &elem)
{
    elems.push_back(elem);
}

template 
void Stack::pop()
{
    if(elems.empty())
    {
        std::out_of_range("Stack:: pop() empty stack");
    }
    elems.pop_back();
}

template 
T Stack::top() const
{
    if(elems.empty())
    {
        throw std::out_of_range("Stack::top() empty stack");
    }
    return elems.back();
}

#endif // STACKDEF_H


    具体的使用示例包含模型

//stacktest1.cpp
#include 
#include "stackdef.h"

int main()
{
    try {
        Stack intStack;
        intStack.push(5);
        intStack.push(69);
        std::cout << "intStack.top()========" << intStack.top() << std::endl;
        intStack.pop();
        std::cout << "intStack.top()========" << intStack.top() << std::endl;
        intStack.pop();
        std::cout << "intStack.top()========" << intStack.top() << std::endl;
    } catch (std::exception const &ex) {
        std::cerr << "exception ====" << ex.what() << std::endl;
    }
    std::cout << "Hello World!" << std::endl;
    return 0;
}

C++template 显示实例化_第1张图片
    
    显示实例化模板

//stack_inst.cpp
#include "stackdef.h"

#include 
template Stack::Stack();

template Stack::Stack();
template void Stack::push(std::string const &elem);
template std::string Stack::top() const;

int main()
{
    Stack intStack;
    intStack.push(96);
    std::cout << "intStack.top========" << intStack.top() << std::endl;

    Stack doubleStack;
    doubleStack.push(73.8);
    std::cout << "doubleStack.top=====" << doubleStack.top() << std::endl;

    Stack floatStack;
    floatStack.push(65.3f);
    std::cout << "floatStack.top======" << floatStack.top() << std::endl;

    Stack stringStack;
    stringStack.push("hello");
    stringStack.push("world");
    std::cout << "stringStack.top=====" << stringStack.top() << std::endl;

    return 0;
}

C++template 显示实例化_第2张图片

你可能感兴趣的:(C++,template学习笔记,C++,template)