class P
{
};
template< typename P >
class C : public P
{
public:
void f()
{
P::f();
}
};
int main() {
C<P> c1;
return 0;
}
以防我的问题留下任何误解的余地,这是一个代码示例。如果C
不是模板但是直接从P
继承,那么样本将无法编译,因为显然函数f()
尝试在基类上调用函数{ {1}}这是不存在的。
但是,如果P
被模板化,那么只有在实际调用C
时才会获取此信息。
我想知道为什么会有这种差异。在这两个实例中f()
都将是死代码并且无论如何都会被剥离,但程序在非模板场景中是不正确的。
答案 0 :(得分:19)
实际上,您发布的程序并不是格式错误。而“隐式实例化”C<P> c1;
实例化所有成员声明,
当引用特化时,隐式实例化成员的特化 在需要成员定义存在的上下文中
[N4140,14.7.1(2)]由于您从未使用C<P>::f
,因此永远不需要其定义,因此永远不会实例化。
这与
之类的“显式实例化”不同template class C<P>;
将实例化C<P>
所有成员的定义,从而导致错误。
答案 1 :(得分:8)
因为允许仅使用实际形成良好的函数是有意义的。
取vector::push_back(const T&)
,这需要T
可复制。但即使vector
是可移动的非可复制类型,您仍然可以使用T
的大部分内容。
答案 2 :(得分:5)
在模板类中,标识符P
是模板参数typename,不引用之前定义的class P
。所以你不能说P::f()
不存在,因为你不知道哪个类将替换参数P
。
之后,当您调用模板来声明c1
变量时,不需要该函数,因此没有“死代码” - 只有一个模板,它从未扩展到实际代码。
答案 3 :(得分:3)
如果我编写一个继承自P
的非模板类,则从成员函数调用该类上不存在的函数显然是一个错误,因为它没有任何用处。
但是,如果C
是模板类,则该错误调用可能对某些其他P
有效。也许该成员函数代表一些支持某些给定接口的类型的扩展功能。 C
可以从某些外部库中实例化,我在实例化P
时不知道。因此,为模板类中的未使用函数抛出编译器错误可能对某些类型有效会限制模板的表达能力。它还会降低编译时间,二进制大小等,因为在不使用类型时不需要为类型生成不需要的模板函数。
答案 4 :(得分:2)
未使用变量C<P> c1;
,永远不会调用C::f()
函数。编译器在使用之前不会创建函数体。这是一个简单的优化,可以加快编译速度。