在C ++模板继承中强制完全模板实例化?

时间:2015-04-21 13:37:49

标签: c++ templates c++11 inheritance instantiation

我们都知道C ++类模板不会生成未使用的成员函数,如下所示:

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,因此没有为其生成实际代码,因此不会发生编译错误。

现在,让我们介绍一个定义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:实例化'void A :: WrongFunction(T)[用T =   int]':prog.cc:39:1:从这里需要prog.cc:24:20:错误:没有   匹配'operator-'(操作数类型是'const char [4]'和   'std :: vector&gt;')        auto a =“abc” - v;

我对工作流程的理解,主要是,我说创建一个A的实例,然后编译器找到A的模板声明(注意A不是类; A<SomeType>是。) 。哇,这取决于Base<int>。很好,编译器然后找到Base的模板声明,将int插入到T所持的位置 - 现在我们有类Base<int>的声明,但是没有生成定义 - 毕竟,我们没有提供模板用于Base<SomeType>的定义生成,并且没有人曾创建Base<int>的任何实例或已在实例上调用函数。没关系。然后编译器扩展Base<int>的声明并生成A<int>的声明。等等,在下一行,调用RightFunction。因此,编译器为A找到RightFunction的模板定义并插入特定类型int,并为A生成成员函数定义。

由于永远不会调用WrongFunction(也没有涉及特殊化;也没有显式实例化),编译器甚至不应该尝试生成A<int> :: WrongFunction的代码---我的问题是,到底是怎么回事?

编译器:gcc 4.9.2

感谢。

1 个答案:

答案 0 :(得分:4)

来自N3337,§14.7.1/ 10 [temp.inst]

  

实现不应隐式实例化不需要实例化的类模板的函数模板,成员模板,非虚拟成员函数,成员类或静态数据成员。 如果虚拟成员函数不会被实例化,则实现是否隐式实例化类模板的虚拟成员函数是未指定的。 ...

因此即使您从未调用虚拟成员函数,实现虚拟成员函数也是合法的。

实际上,情况可能总是如此,因为在实例化类模板时,编译器还需要实例化该类的vtable,该类必须填充虚拟成员函数的地址。