我认为一个显式的实例化请求也会自动实例化所有基类成员,但我linker error: unresolved external symbol "public: void Base<int>::foo(int)"在使用Visual Studio 2008或2010构建此代码时得到了一个.
请注意,向foo()内部添加调用会bar()强制编译器实例化Base<int>::bar()并且构建成功,因此编译器似乎具有实例化所需的所有信息foo().
显然,Base<int>在source.cpp中显式实例化允许构建成功,但是在显式实例化派生类时,需要显式实例化任何依赖基类似乎很愚蠢.
这是正常的吗?我无法找到关于这个问题的标准.
header.h
template<typename T>
class Base {
public:
void foo();
};
template<typename T>
class Derived : public Base<T> {
public:
void bar();
};
Run Code Online (Sandbox Code Playgroud)
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>;
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include "header.h"
int main() {
Derived<int> d;
d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)"
}
Run Code Online (Sandbox Code Playgroud)
编辑:
看起来标准表示只有类的成员才能通过显式类实例化进行实例化,因此链接器错误在我的示例中是合理的.
请注意,类由class-head {member-specification}定义,并且"类定义中的成员规范声明了类的完整成员集;不能在其他地方添加成员." 因此,成员只在大括号{}之间,并且公共基类成员不会成为派生类的成员,它们只能从派生类或派生类的对象访问.
我唯一剩下的问题是为什么标准规定类模板的显式实例化只实例化成员而不是基类成员?我的猜测是,这可以更好地控制明确实例化的内容.使用显式模板类实例化的人很可能在与派生类定义不同的文件中具有基类定义,并且将分别显式地实例化每个类定义.
标准说
类模板特化的显式实例化意味着实例化其所有以前未明确专用于包含显式实例化的转换单元的成员.
换句话说,它并没有强制要求依次显式地实例化基类.它将导致它们的隐式实例化,它们不会预先实例化它们的成员定义.标准中的一些丑陋小故障是关于某个文本是否表示"成员"意味着"直接"或"继承"成员,因为对于编写标准措辞的人来说,这通常似乎是"显而易见的",但对于一个人读它.C++ 0x添加了一些说明(它在显式实例化声明和C++ 03没有的定义之间也有区别,但即使忽略它,C++ 0x措辞还包含更多的洞察力):
An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below. [ Note: In addition, it will typically be an explicit instantiation of certain implementation-dependent data about the class. — end note ]