C++ 模板继承中强制的完整模板实例化?
Full template instantiation forced in C++ template inheritance?
我们都知道C++ class模板不会生成不用的成员函数,如下图:
template<typename T>
class A
{
public:
void WrongFunction(T t);
void RightFunction(T t);
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
由于在 main 中没有调用 WrongFunction,因此没有为其生成实际代码,因此不会发生编译错误。
现在,让我们介绍一个抽象基础 class,它定义了 class A(基本上是模板继承)的接口:
template<typename T>
class Base
{
public:
virtual void RightFunction(T t) = 0;
virtual void WrongFunction(T t) = 0;
};
template<typename T>
class A : Base<T>
{
public:
void WrongFunction(T t) override;
void RightFunction(T t) override;
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
编译器突然拒绝工作:
prog.cc: In instantiation of 'void A::WrongFunction(T) [with T =
int]': prog.cc:39:1: required from here prog.cc:24:20: error: no
match for 'operator-' (operand types are 'const char [4]' and
'std::vector >')
auto a = "abc" - v;
我对工作流程的理解是,主要是,我说创建一个A的实例。好的,编译器然后找到A的模板声明(注意A不是class; A<SomeType>
是。)。哇,这取决于Base<int>
。很好,然后编译器找到 Base 的模板声明,将 int 插入到 T 所在的位置 - 现在我们有 class Base<int>
的声明,但没有生成定义 - 毕竟,我们做了没有为 Base<SomeType>
提供定义生成模板,并且没有人创建过 Base<int>
的任何实例或调用过该实例的函数。没关系。然后编译器扩展 Base<int>
的声明并生成 A<int>
的声明。等等,在下一行,调用了 RightFunction。所以编译器找到A的RightFunction的模板定义并插入特定类型的int并生成A的成员函数定义。
因为从未调用 WrongFunction(也没有涉及专门化;也没有显式实例化),编译器甚至不应该尝试为 A<int>
::WrongFunction 生成代码 ---我的问题是,这到底是怎么回事?
编译器:gcc 4.9.2
谢谢。
来自 N3337,§14.7.1/10 [temp.inst]
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. ...
因此,实现实例化虚拟成员函数是合法的,即使您从未调用过它。
在实践中,这很可能总是如此,因为在实例化一个 class 模板时,编译器还需要为那个 class 实例化 vtable,它必须填充虚拟地址成员函数。
我们都知道C++ class模板不会生成不用的成员函数,如下图:
template<typename T>
class A
{
public:
void WrongFunction(T t);
void RightFunction(T t);
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
由于在 main 中没有调用 WrongFunction,因此没有为其生成实际代码,因此不会发生编译错误。
现在,让我们介绍一个抽象基础 class,它定义了 class A(基本上是模板继承)的接口:
template<typename T>
class Base
{
public:
virtual void RightFunction(T t) = 0;
virtual void WrongFunction(T t) = 0;
};
template<typename T>
class A : Base<T>
{
public:
void WrongFunction(T t) override;
void RightFunction(T t) override;
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
编译器突然拒绝工作:
prog.cc: In instantiation of 'void A::WrongFunction(T) [with T = int]': prog.cc:39:1: required from here prog.cc:24:20: error: no match for 'operator-' (operand types are 'const char [4]' and 'std::vector >') auto a = "abc" - v;
我对工作流程的理解是,主要是,我说创建一个A的实例。好的,编译器然后找到A的模板声明(注意A不是class; A<SomeType>
是。)。哇,这取决于Base<int>
。很好,然后编译器找到 Base 的模板声明,将 int 插入到 T 所在的位置 - 现在我们有 class Base<int>
的声明,但没有生成定义 - 毕竟,我们做了没有为 Base<SomeType>
提供定义生成模板,并且没有人创建过 Base<int>
的任何实例或调用过该实例的函数。没关系。然后编译器扩展 Base<int>
的声明并生成 A<int>
的声明。等等,在下一行,调用了 RightFunction。所以编译器找到A的RightFunction的模板定义并插入特定类型的int并生成A的成员函数定义。
因为从未调用 WrongFunction(也没有涉及专门化;也没有显式实例化),编译器甚至不应该尝试为 A<int>
::WrongFunction 生成代码 ---我的问题是,这到底是怎么回事?
编译器:gcc 4.9.2
谢谢。
来自 N3337,§14.7.1/10 [temp.inst]
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. ...
因此,实现实例化虚拟成员函数是合法的,即使您从未调用过它。
在实践中,这很可能总是如此,因为在实例化一个 class 模板时,编译器还需要为那个 class 实例化 vtable,它必须填充虚拟地址成员函数。