【发布时间】:2010-09-13 22:51:58
【问题描述】:
我认为显式实例化请求也会自动实例化所有基类成员,但在使用 Visual Studio 2008 或 2010 构建此代码时,我得到了 linker error: unresolved external symbol "public: void Base<int>::foo(int)"。
请注意,在bar() 中添加对foo() 的调用会强制编译器实例化Base<int>::bar() 并且构建成功,因此编译器似乎拥有实例化foo() 所需的所有信息。
显然,在 source.cpp 中显式实例化 Base<int> 可以使构建成功,但在显式实例化派生类时需要显式实例化任何依赖基类似乎很愚蠢。
这正常吗?我找不到标准关于这个问题的说法。
header.h
template<typename T>
class Base {
public:
void foo();
};
template<typename T>
class Derived : public Base<T> {
public:
void bar();
};
source.cpp
#include "header.h"
template<typename T>
void Base<T>::foo() { }
template<typename T>
void Derived<T>::bar() {
// this->foo(); // adding this forces instantiation of foo()???
}
template class Derived<int>;
main.cpp
#include "header.h"
int main() {
Derived<int> d;
d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)"
}
编辑:
看起来标准说只有类的成员才能通过显式类实例化来实例化,所以在我的示例中链接器错误是合理的。
注意一个类是由class-head { member-specification }定义的,“类定义中的成员规范声明了类的全部成员;不能添加任何成员别处。”所以成员只在大括号 { } 之间,公共基类成员不会成为派生类的成员,它们只能从派生类或派生类的对象中访问。
我剩下的唯一问题是为什么标准规定类模板的显式实例化只实例化成员而不是基类的成员?我的猜测是,这可以更好地控制在何处显式实例化的内容。使用显式模板类实例化的人很可能会将基类定义与派生类定义放在不同的文件中,并且会分别显式实例化每个。
【问题讨论】:
-
是否为基类的派生触发器实例化添加显式构造函数?我怀疑编译器试图不做不必要的工作。拥有一个构造函数可能会让它意识到它也需要构造 Base,这可能会触发它。另外,你试过 gcc 或其他编译器吗?
-
添加带或不带参数以及带或不带关键字“explicit”的构造函数不会触发基类 foo() 的实例化,但会触发派生成员 bar() 对 foo() 的调用隐式实例化。