据我的理解(C++公共知识,项目61;Solaris Studio C++用户指南),一个模板类的显式实例化将导致它的所有成员被实例化。但是,我发现Solaris Studio C++编译器的情况并非如此。由于此编译器的行为通常与其他编译器非常不同,同时仍然遵循规范(通常在更严格的意义上),因此我向任何C++模板专家询问我所看到的行为是否有效。
我的情况是,我有一个模板类“派生”,它继承自一个模板类"Base“专门用于”派生“。"Base“包含一个静态变量"tracer”,它必须在编译后出现在对象文件中(在我的完整代码中,这与向工厂注册“派生”有关)。大多数编译器(GCC、Open64、Intel、Clang、Visual C++)都是这样的。但是,在Solaris Studio中,只有当“派生”的构造函数在其定义中没有实现时才会发生这种情况,否则,"tracer“不会放在对象文件中(并且”派生“不会在Factory中注册)。
下面是一些简单的代码来演示这个问题:
Base.h:
#ifndef BASE_H_
#define BASE_H_
template<typename T>
class Base {
public:
Base() : dummy_(g_tracer_) { }
private:
bool dummy_;
static bool g_tracer_;
};
template<typename T>
bool Base<T>::g_tracer_ = true;
#endif // BASE_H_DerivedA.cc:
#include "Base.h"
template<typename T>
class DerivedA : private Base<DerivedA<T> > {
public:
DerivedA(int val);
T GetVar() const;
private:
T var_;
};
template<typename T>
DerivedA<T>::DerivedA(const int val) : var_(val) { }
template<typename T>
T DerivedA<T>::GetVar() const { return var_; }
// Explicit Instantiation
template class DerivedA<double>;DerivedB.cc:
#include "Base.h"
template<typename T>
class DerivedB : private Base<DerivedB<T> > {
public:
DerivedB(int val) : var_(val) { }
T GetVar() const;
private:
T var_;
};
template<typename T>
T DerivedB<T>::GetVar() const { return var_; }
// Explicit Instantiation
template class DerivedB<double>;如果我用sunCC -c编译“sunCC -c”文件,并对结果的对象文件运行nm,“德里维达A.o”包含"g_tracer_“(0000000000000000 V __1cEBase4nIDerivedA4Cd___Jg_tracer__)的符号,但”德里维德B.o“不包含”g_tracer_“符号。(注意:即使我使用-template=wholeclass选项,输出中仍然不存在符号。)使用任何其他编译器,两个目标文件都将包含一个与"g_tracer_“相对应的符号。
这是有效的行为,还是一个晦涩的编译器错误?我对C++规范的了解并不足以让我相信这两种方式。(实际上,我在这里看到了一个答案,表明显式实例化可能不会实例化基类成员,所以现在我特别困惑。)如对此事有任何澄清,我将不胜感激。谢谢!
发布于 2011-09-04 11:21:51
嗯,您是否真的尝试过设置一个使用实例化类的程序?因为您只是创建一个“库”(这是标准根本不谈论的事情),我相信编译器(或者更好的是图书管理员)可以做它想做的任何事情。试着建立一个把所有东西连接在一起的程序。我假设,如果没有一些关于未使用符号实例化的特定链接器配置,或者没有一些强制使用的诡计,那么最终您将完全没有g_tracers的实例化--链接器将根本不会将它们添加到程序中。
干杯,
保罗
https://stackoverflow.com/questions/7298116
复制相似问题