C++中export关键字的尴尬处境
【原创文章,转载请保留或注明出处:http://blog.csdn.net/hikaliv/article/details/4474835】
分离编译模式(Separate Compilation Model)允许在一处翻译单元(Translation Unit)中定义(define)函数、类型、类对象等,在另一处翻译单元引用它们。编译器(Compiler)处理完所有翻译单元后,链接器(Linker)接下来处理所有指向 extern 符号的引用,从而生成单一可执行文件。该模式使得 C++ 代码编写得称心而优雅。
然而该模式却驯不服模板(Template)。标准要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。
以优雅著称的 C++ 是不能容忍有此“败家仔儿”好好活着的。标准 C++ 为此制定了“模板分离编译模式(Separation Model)”及 export 关键字。然而由于 template 语义本身的特殊性使得 export 在表现的时候性能很次。编译器不得不像 .net 和 java 所做的那样,为模板实体生成一个“中间伪代码(IPC,intermediate pseudo - code)”,使得其它翻译单元在实例化时可找到定义体;而在遇到实例化时,根据指定的 typename 实参再将此 IPC 重新编译一遍,从而达到“分离编译”的目的。因此,该标准受到了几乎所有知名编译器供应商的强烈抵制。
谁支持 export 呢?Comeau C/C++ 和 Intel 7.x 编译器支持。而以“百分百支持 ISO ”著称的 VS 和 GCC 却对此视而不见。真不知道这两大编译器“百分百支持”的是哪个版本的 ISO。在 VS 2008 中,export 关键字在 IDE 中被标蓝,表示 VS IDE 认识它,而编译时,会用警告友情提示你“不支持该关键字”,而配套的 MSDN 9 中的 C++ keywords 页则根本查不到该关键字;而在 VS 2010 中,就没那么客气了,尽管 IDE 中仍然会将之标蓝,但却会直截了当地报错。
参考:
《VS 2010 并不支持 C++ 0x 标准中的 extern template》
模板具体化可以分离编译,且要是不以内联函数实现成员函数时,则为了在多个文件中使用,则必须分开,在另一个文件中定义成员函数。
示例。
头文件Stack.h
#ifndef STACK_H_
#define STACK_H_
namespace util
{
//模板类
template <class T>
class Stack
{
private:
enum{SIZE=10};
T a[SIZE];
int top;
public:
Stack():top(0){}
bool isEmpty()const;
bool isFull()const;
bool push(const T el);
bool pop(T &p);
};
//模板具体化
template <>
class Stack<char *>
{
private:
enum{SIZE=10};
char * a[SIZE];
int top;
public:
Stack():top(0){}
bool isEmpty()const;
bool isFull()const;
bool push( char * const el); //模板的类型是指针,故此处因为常指针
bool pop(char * &p);
};
//编译器没实现关键字export,故必须在此处实现
template <class T>
bool Stack<T>::isEmpty()const
{
return 0==top;
}
template <class T>
bool Stack<T>::isFull()const
{
return SIZE==top;
}
template <class T>
bool Stack<T>::push(T el)
{
if(top>=SIZE)
return false;
a[top++]=el;
return true;
}
template <class T>
bool Stack<T>::pop(T &p)
{
if(0 == top)
return false;
p=a[--top];
return true;
}
//模板实例化(具有内部连接性,故可在头文件中定义实例化类
template class Stack<int>;
// template class Stack<char *>; //会重复定义,故注释掉
template class Stack<const char *>;
}
#endif
模板具体化实现Stack.cpp
在Vc中可以编译连接通过,在G++中认为成员函数不匹配,高手知道,还望告知
#include<iostream>
#include"Stack.h"
namespace util
{
template <>
bool Stack<char *>::isEmpty()const
{
return 0==top;
}
template <>
bool Stack<char *>::isFull()const
{
return SIZE==top;
}
template <>
bool Stack<char *>::push(char * const el)
{
if(top>=SIZE)
return false;
a[top++]=el;
return true;
}
template <>
bool Stack<char *>::pop(char * &p)
{
using std::cout;
using std::endl;
if(0 == top)
return false;
p=a[--top];
cout<<"具体化"<<endl;
return true;
}
}
测试main.cpp
#include<iostream>
#include"Stack.h"
using namespace util;
typedef Stack<int> stack;
int main()
{
using std::cout;
using std::endl;
stack s;
int a[]={2,3,4,5,7,8};
int i=0;
for( i=0;i<sizeof a/sizeof(int);i++)
{
cout<<a[i]<<" ";
if(!s.isFull())
s.push(a[i]);
}
int tmp=0;
cout<<endl;
while(s.pop(tmp))
{
cout<<tmp<<" ";
}
cout<<endl;
Stack<char *> s1;
char t[]="bao";
char t1[]="af";
char t2[]="trqtr";
char *ch[]={t,t1,t2};
for( i=0;i<sizeof ch/sizeof(int);i++)
{
cout<<ch[i]<<" ";
if(!s1.isFull())
s1.push(ch[i]);
}
char *tmp1;
cout<<endl;
while(s1.pop(tmp1))
{
cout<<tmp1<<" ";
}
cout<<endl;
Stack<const char *> s2;
const char *ch1[]={"faf","ta","tet"};
for( i=0;i<sizeof ch1/sizeof(int);i++)
{
cout<<ch1[i]<<" ";
if(!s2.isFull())
s2.push(ch1[i]);
}
const char *tmp2;
cout<<endl;
while(s2.pop(tmp2))
{
cout<<tmp2<<" ";
}
return 0;
}
参考文献:
http://hi.baidu.com/taoshui123/item/d971f088a337a056e63d19eb