关于模板实例化后的本身的连接问题

本文主要讨论的是在模板函数代码采用内嵌模式进行组织的时候的调用时候的连接问题。

本文采用的编译器为:g++-4.4.real (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3

在模板在编译单元中被调用的时候,如果能找到模板的定义,则会对其进行实例化,因此当模板使用嵌入式进行组织代码的时候(即模板的声明和定义均放在.h文件中),当这个文件被引用在不同的编译单元的时候,会被编译多次,生成多个实例。

如果生成了多个实例,那么为什么在连接的时候没有报连接错误呢,这个关键在于编译器在生成代码的时候,给模板实例的符号赋予的性质有关系,通过系统工具nm查看发现模板函数实例化后的性质为“W”(未明确指定的弱链接符号;同链接的其他对象文件中有它的定义就用上,否则就用一个系统特别指定的默认值。)。因此连接器在连接的时候只是用第一个而忽视其他实例。详细情况见下面实例。

自己做的一个实验

// template1.h

  1// basics/myfirst2.hpp

  2

  3#ifndef TEMPLATE_H

  4#define TEMPLATE_H

  5

  6#include <iostream>

  7#include <typeinfo>

  8

  9

 10// declaration of template

 11template <typename T>

 12void print_typeof (T const&);

 13

 14// implementation/definition of template

 15template <typename T>

 16void print_typeof (T const& x)

 17 {

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

 19 }

 20

 21#endif // TEMPLATE_H

 

// use_template.h

  1#ifndef USE_TEMPLATE_H

  2#define USE_TEMPLATE_H

  3void use_template(void);

  4static void use_template2(void);   

  5#endif  //  USE_TEMPLATE_H

 

// use_template.cpp                 

  1#include <iostream>

  2#include "use_template.h"

  3#include "template1.h"

  4using std::cout;

  5void use_template(void) {

 6   int i = 0;

 7   print_typeof(i);

  8 }

  9void use_template2(void) {

 10   inti = 0;

 11  print_typeof(i);

 12 }

 

 

// use_template_main.cpp

  1#include <iostream>

  2#include <typeinfo>

  3#include "use_template.h"

  4// #include "template1.h"

  5using std::cout;

  6 // 具体用哪个.o文件中的print_typeof函数由编译时候,输入的文件顺序决定

  7template <typename T>

  8void print_typeof (T const& x)

  9 {

 10  std::cout << typeid(x).name() << std::endl<<"this is in main file" << std::endl;

 11 }

 12/*

 13// 会报和上面重复定义

 14template <typename T>

 15void print_typeof (T const& x)

 16 {

 17  std::cout << typeid(x).name() << std::endl<<"this is in main file" << std::endl;

 18 }

 19*/

 20// 不会报重复定义,use_template中用的是模板生成的,而本文件中的print_typeof则用的是当前函数

 21// void print_typeof (int const& x)

 22// {

 23//   std::cout << typeid(x).name()<< std::endl << "this is in main file" <<std::endl;

 24// }

 25int main (int argv, char *argc[]) {

 26  use_template();

 27   inti = 0;

 28  print_typeof(i);

 29 }

 30// 不会被用到

 31void print_typeof (int const& x)

 32 {

 33  std::cout << typeid(x).name() << std::endl <<"this is in main file end" << std::endl;

 34 }

 

// 结果1

ubuntu:~/C++/template$g++ use_template.cpp use_template_main.cpp

ubuntu:~/C++/template$./a.out

i

i

 

 

// 结果2

ubuntu:~/C++/template$g++ use_template_main.cpp use_template.cpp

ubuntu:~/C++/template$./a.out

i

thisis in main file

i

thisis in main file

 

用nm查两个点o文件结果如下:

 

ubuntu:~/C++/template$g++ use_template_main.cpp use_template.cpp -c

ubuntu:~/C++/template$nm use_template.

use_template.cpp  use_template.h    use_template.o   

ubuntu:~/C++/template$nm use_template.o

00000074t _GLOBAL__I__Z12use_templatev

00000000 W _Z12print_typeofIiEvRKT_

00000000T _Z12use_templatev

00000034t _Z41__static_initialization_and_destruction_0ii

0000001at _ZL13use_template2v

00000000W _ZNKSt9type_info4nameEv

         U _ZNSolsEPFRSoS_E

         U _ZNSt8ios_base4InitC1Ev

         U _ZNSt8ios_base4InitD1Ev

         U _ZSt4cout

         U_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_

00000000b _ZStL8__ioinit

         U_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

         U _ZTIi

         U __cxa_atexit

         U __dso_handle

         U __gxx_personality_v0



ubuntu:~/C++/template$nm use_template_main.o

000000bet _GLOBAL__I_main

00000000 W _Z12print_typeofIiEvRKT_

00000029T _Z12print_typeofRKi

         U _Z12use_templatev

0000007et _Z41__static_initialization_and_destruction_0ii

00000000W _ZNKSt9type_info4nameEv

         U _ZNSolsEPFRSoS_E

         U _ZNSt8ios_base4InitC1Ev

         U _ZNSt8ios_base4InitD1Ev

         U _ZSt4cout

         U_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_

00000000b _ZStL8__ioinit

         U_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

         U _ZTIi

         U __cxa_atexit

         U __dso_handle

         U __gxx_personality_v0

00000000T main

 

根据nm的man中的说明,W表示:未明确指定的弱链接符号;同链接的其他对象文件中有它的定义就用上,否则就用一个系统特别指定的默认值。(从上述结果来看,如果有多个实现,则从中选取一个,所有参与连接的文件都用同一个实现。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值