栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++模板编程(4)---实际运用模板:置入式模型(InclusionModel)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++模板编程(4)---实际运用模板:置入式模型(InclusionModel)

有很多方法可以组织我们的模板template程序代码,本文介绍常见的一种方式:置入式模型。

1. 链接错误(Link Error)

大多数C,c++程序员大致按以下方式来组织他们的non-template程序代码:

Classes和其他类型被全体放置于头文件(header files)。通常头文件的后缀名称(扩展名)为.hpp(或.H, .h,.hh,.hxx 等等)。

全局变量和non-inline函数只在头文件中置入声明语句,定义式则置于.c文件中。这里的.c文件是个统称,通常其后缀名称(扩展名)为.cpp(或.c,.C,.cc,.cxx等等)。

这种方式运作良好,程序能够轻易找到各个类型的定义,并避免一个变量或函数被多次重复定义,于是连接器(linker)可以正常工作。

但是模板程序代码在这里跟非模板程序不一样,举例来说,我们把 template声明于某个头文件:

//myfirst.hpp

#ifndef MYFIRST_HPP

#define MYFIRST_HPP

//template 声明语句

template

void print_typeof (T const&);

#endif

print_typeof()是一个简单的辅助函数,它打印参数的类型信息(type information)。函数的实际代码被置于一个.c文件中:

//myfirst.cpp

#include

#include

#include "myfirst.hpp"

//template定义式

template

void print_typeof (T const& x)

{

        std::cout << typeid(x).name() << std::endl;

}

 这个例子中使用typeid运算符,把参数的类型以字符串形式打印出来。

此后,我们又在另外一个c文件中使用这个template,并将template声明语句(所在的文件)以

#include包含进来:

//main.cpp

#include "myfirst.hpp"

int main()

{

        double ice=3.0;

        print_typeof(ice);

}

大多数编译器可以正确编译上述代码,但会报告一个链接错误,表示无法找到print_typeof()函数的定义。

    错误的原因在于,function template print-typeof()的定义没有被实例化。为了实例化一个模板,编译器必须知道以哪一份定义式以及哪些模板参数对它实例化。不幸的是先前这个例子中,这两项信息被分置在两个分开编译的文件中。因此,当编译器看到对print_typeof()的调用时,看不到其定义,无法以double类型来实例化print_typeof()。于是编译器假设这个template的定义位于其他某处,因而只生成一个对该定义的reference,并将这个reference所指的定义式留给连接器去解决(resolve)。另一方面,当编译器处理myfirst.cpp时,它又察觉不到该以哪个自变量类型来实例化其定义式。

2. 把模板放在头文件中(Header Files)

    就像处理宏macro和内联函数inline一样,解决上面问题的常见办法是:把template定义式放到其声明语句所在的头文件中。面对前例,我们可以在myfirst.hpp最后一行加入:

#include “myfirst.cpp”

也可以在用到该template的每一个.c文件中#include “myfirst.cpp”.

第三种方法,也是最常用的方法,完全不用myfirst.cpp,声明和定义都写在文件myfirst.hpp中:

//myfirst.hpp

#ifndef MYFIRST_HPP

#define MYFIRST_HPP

#include

#include

// 声明语句

template

void print_typeof (T const &)

//定义语句

template

void print_typeof(T const& x)

{

        std::cout << typeid(x).name() << std::endl;

}

#endif

这种template组织法称为置入式模型inclusion model。现在上面程序可以正确编译、链接与运行。

需要引起注意的是:

包含myfirst.hpp的代价比较大。此物所谓代价,不仅指template定义式的体积增大,也包括含入myfirst.hpp中其他的文件,比如和。我们会发现,可能导致成千上万的代码被包含进来,因为诸如也是以此种方式来定义template的。

尽管存在上面的问题,还是强烈推荐:只要有可能,尽量用置入式模型inclusion model来组织模板代码。

另外一个关于置入式模型的考虑是,与内联函数(inline function)和宏(marco)明显不同的是,非内联函数模板function template并不在调用端被展开。每当它们被实例化一次,编译器便从头创建一份函数拷贝。这个过程是完全自动化的,编译器可能最终在不同的文件中创建同一个模板实例化的两份拷贝,这时连接器会报错。但理论上,不需要程序员操心,这应该是编译系统的事。

最后要指出的是,

   本文中对于function template所谈的内容,也适用于类模板class template的成员函数和static 成员变量。当然也同样适用于成员函数模板member function templates。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982359.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号