小众知识

首页 > 正文

关于模板的显式实例化声明的问题

在一个程序文本文件中出现了模板的显示实例化声明,比如template class Queue;如果整个程序都没有用到这样的实例(指Queue),而是用到其他实例,如Queue、Queue等,那么是否上述声明变得毫无作用?

    当一个程序由多个文件组成,由多人来完成,在一个程序文本文件中的显式实例化声明如何能“预见”其他人在其他文件中使用的模板实例,从而达到改善编译效能的目的?  

 Andy84920 发表于:2003-11-04 23:01:19
得分:0 

1>
如果你确信"没有用到这样的实例(指Queue)"那么当然没有用.
因为本来不用就是多余,而且C++信奉"只为用到的东西付出代价".

2>
这个基本上就要看哪种情况使用的概率了吧?不太清楚!
这样就直接给出使用概率大的实例化声明咯!

 xueweizhong 发表于:2003-11-04 23:11:11
得分:100 

举个例子来说:
IO流的
用户看到的是头文件中的:
typedef basic_ostream > ostream;
extern ostream cout;

因为这里有extern, 所以编译器看到cout时不会去实例化
basic_ostream类的成员函数(甚至许多成员函数的实现并
不在头文件中)。

而实现者在自己的cpp文件中实现了这些头文件中没有的成员函数,
注意这些成员函数现在还是模板类的成员函数。

然后在cpp的最后写上
template class basic_ostream >;
basic_ostream > cout;

(现实中的细节差异很大,这里只是举例说明)

在cout的定义点能看到模板类的全部实现代码,所以定义可以成立。

而在用户使用时,它不能实例化basic_ostream模板的其他参数版本,
因为它看不到实现源码。这限制了用户的使用方式:

1:只能使用预定义的几种basic_ostream<...>的版本。
2:隐藏了部分实现代码,这部分代码不需要在用户的代码中出现,
   节约了编译时间。
3:用户要实现其他模板参数的basic_ostream几乎是不可能的,
   然后它们找到实现者,在实现者的cpp里添加这个特殊化。
   这导致大家分工明确。

 GreenCode 发表于:2003-11-06 09:19:43
得分:0 

THX xueweizhong(薛卫忠)
看了你的发言后,立刻写了以下程序:
//foobar.h
template 
class Foobar
{
public:
  Foobar(T val):_member(val) {}
  Foobar& add(Foobar&);
  Foobar& sub(Foobar&);
private:
  T _member;
};

//foobar.cpp
#include "foobar.h"

template 
Foobar& Foobar::add(Foobar& t)
{
  _member += t._member;
  return *this;
}

template 
Foobar& Foobar::sub(Foobar& t)
{
  _member -= t._member;
  return *this;
}

template class Foobar;

//app.cpp
#include "foobar.h"

int main()
{
  Foobar fd(1.0), fd1(1.2), fd2(1.4);
  fd.add(fd1);
  fd.sub(fd2);
}
在Dev-C++ 4.9.8.4下编译运行无误。
在C++Primer(中文版)中讲到显式实例声明允许程序员控制模板实例化发生的时间
可否这样理解,显式实例声明相当于一个“开关”,只要出现,必然导致模板函数成员的实例化(哪怕今后并未用到函数成员的实例),在app.cpp中,成员函数add()和sub()的调用点看不到模板函数成员的定义,但函数成员已在foobar.cpp中实例化。


 limd 发表于:2003-11-06 09:38:23
得分:0 

好像只有用了,才会进行实例化的 

 xueweizhong 发表于:2003-11-06 10:32:51
得分:0 

好象limd说的更加准确一些:
“好象只有用了,才会进行实例化"。

乘这个机会,找几个编译器试一下,然后大家可以
交流一下,呵呵....

还可以去翻翻标准,不过里面好象也说的有点含糊其词。 

 GreenCode 发表于:2003-11-06 20:35:19
得分:0 

C++程序设计语言,附录C13.10
“当一个类模板被显式实例化时,它的所有成员函数都将实例化。”(When a class template is explicitly instantiated, every member function is also instantiated)

 xueweizhong 发表于:2003-11-06 22:48:22
得分:0 

>to GreenCode:
楼主从CPL中也找到了,呵呵,CPL果然无所不包。
我在C++STD的template chapter(8?)中的explicit-instantiated那
一小节也找到类似的话。
我的理解是:
1)如果显式实例化函数模板,那么必须在显式实例化点看到模板函数的定义
2)为模板成员函数显式实例化,和上面相同
3)为模板静态数据成员显式实例化,和上面相同
4)为类模板显式实例化,必须在显式实例化点看到模板函数的定义。

在上面4)的情况下,将会导致类模板的成员函数和静态变量
的隐式实例化--就是指上贴里楼主所说。

关于隐式实例化,问题则要复杂一些:

1)这个情况要简单一些:
   类模板的隐式实例化点需要看到模板类的定义
   (因为类定义可以出现在多个translation-unit中,
     这个不会有太多问题)

2)模板函数的隐式实例化(包括成员函数模板,静态变量模板)
   这个隐式实例化点并不需要看到模板函数的定义,只需看到
   模板函数的声明就可以了。

   #1 如果看到了模板函数的定义,那么一般情况下,
    编译器就会在该translation-unit的obj文件中包含
    实例化后的特殊化版本定义。

   #2 如果没有看到模板函数的定义,那么一般情况下
    编译器没法在该translaiton-unit的obj文件中包含
    实例化后的特殊化版本定义。

   接下来:
   ##1 
   这时,如果没有unit中包含#2的情况,没有obj中包含该定义
   导致链接出错。

   ##2
   如果恰有一个unit中包含#2的情况,恰好有一个定义,
   我们将会一切正常。

   ##3
   如果有多个unit中包含#2的情况,导致多个定义,
   如果这多个定义是一样的,那么编译器在链接时随便选择一个,
   而去掉其他所有的,也将一切正常。

   ##4
   如果在##3中多个定义并不一致,将导致编译器选择的那个会依赖
   于链接顺序,导致很奇怪的错误。

   ##5
    ##1的情况下,虽然所有隐式实例化的单元没有包含定义,但如果
   在其他没有包含隐式实例化的unit内含有一个显式实例化点,那么这个
   定义可以用来作为可用的定义版本,而链接器不会报错。

##4的情况是很危险的,感觉上一切正常,事实却发生了错误,呵呵

楼主举例的代码刚好是:
(属于上面##2的情况)

两个文件中都包含隐式实例化,
其中一个有类模板显式实例化导致,这个隐式实例化点看到了定义。
而另外一个隐式实例化只看到了声明,没有看到定义,
刚好恰在一个unit的obj内产生定义。

这种方式把定义放在cpp里,其他unit不能看到,不会导致多个定义。
刚好具有前面帖子中说的那些优点。

呵呵,说了那么多,很可能有错,请大家指正。 

 xueweizhong 发表于:2003-11-06 22:52:20
得分:0 

上面#1和#2反了,呵呵,大家看成这样吧:

   #2 如果看到了模板函数的定义,那么一般情况下,
    编译器就会在该translation-unit的obj文件中包含
    实例化后的特殊化版本定义。

   #1 如果没有看到模板函数的定义,那么一般情况下
    编译器没法在该translaiton-unit的obj文件中包含
    实例化后的特殊化版本定义。

抱歉。

 GreenCode 发表于:2003-11-07 15:08:34
得分:0 

to xueweizhong:
以上都是C++ Standard里面的话么 

 xueweizhong 发表于:2003-11-07 15:38:53
得分:0 

呵呵,我总结的,如果有错,请兄弟指正。呵呵。

上一篇:怎样把pthread_create的线程函数当作类的成员函数编译通过?
下一篇:请问各位高手,在程序的设计阶段用哪个软件帮忙比较好啊?

分享到: