模板类实例化如何与类继承一起工作?

5

代码

我有以下两个类的片段,分别有独立的源文件和头文件。派生类是一个模板类。

handler.h

class BaseHandler {
public:
    BaseHandler(){}
    BaseHandler(const std::string& directive);
    virtual ~BaseHandler();
    virtual bool operator()();
private:
    const std::string m_directive;
};

template<typename C>
class DirectiveHandler : public BaseHandler {
public:
    DirectiveHandler(const std::string& directive);
    ~DirectiveHandler();
    bool operator()() override;
private:
    std::vector<C> m_configurations;
};

handler.cpp

#include "handler.h"

BaseHandler::BaseHandler(const std::string& directive) : m_directive(directive) {};

BaseHandler::~BaseHandler(){};

template<typename C>
DirectiveHandler<C>::DirectiveHandler(const std::string& directive) :
    BaseHandler(directive) {};

template<typename C>
bool DirectiveHandler<C>::operator()(){ return true; };

main.cpp

#include "handler.h"

template class DirectiveHandler<double>;    //explicit template instantiation

int main(int argc, char *argv[]){
....

根据我的理解,在定义模板之后需要实例化它,这可以通过隐式(省略template class DirectiveHandler<double>;)或显式的方式来实现。
我假设隐式实例化失败是因为在相应的源文件和头文件中分离了定义和声明。
使用上述main.cpp片段时,我得到以下警告:
  1. 警告:显式模板实例化DirectiveHandler<double>将在每个翻译单元中生成一个虚函数表

  2. 警告:在此处需要实例化函数DirectiveHandler<double>::operator(),但没有可用的定义

如果将template class DirectiveHandler<double>更改为extern template class DirectiveHandler<double>;,这两个警告都会消失。我理解为什么警告2被清除了,因为模板类位于handler.cpp中。但我不明白它如何同时清除警告1。
问题:
为什么添加extern关键字会清除警告1(见上文)?

1
@YSC,这个闭包肯定是错误的。OP正在问一个完全不同的问题!我现在重新打开了它。 - SergeyA
1
@SergeyA 但是,CNR(http://coliru.stacked-crooked.com/a/929cc5bb9e589302 "无法重现")。这就是为什么我们要求提供一个mcve的原因。 - YSC
警告1是良性的;多个vtable将在链接时折叠。也可参见此处 - rustyx
1
@YSC,首先,CNR与重复不同。其次,您的复制尝试明显不正确-OP有多个文件和翻译单元,而您只有一个。我还有一种感觉,OP正在使用CLang,如果我是正确的,这是原始问题中缺少的一部分。 - SergeyA
1
@YSC 什么?OP问的是为什么添加extern会消除警告。这与dup有什么关系?我完全看不出你的推理。不幸的是,由于OP似乎对这个问题的兴趣不如我,我将避免进一步的交谈和任何对这个问题的进一步行动。 - SergeyA
显示剩余4条评论
1个回答

3
我假设你正在使用CLang编译你的代码?(据我所知,这是CLang的警告,除非g ++也开始发出它)。 无论如何,对于所提出的问题的答案(我只能假设OP理解其他所有内容),简单的事实是template class DirectiveHandler<double>; - 这是隐式模板实例化定义,它产生vtbl等。 (事实上,警告针对.cpp文件发出可能是一个错误,但OP没有询问它)。 另一方面,extern template class DirectiveHandler<double>;不是定义。 它是一个声明,本身不会触发vptr的生成,因此您看不到警告。

我目前使用qt creator(集成开发环境)。它使用Clang静态代码分析器,但代码是由g++-6编译的。我承认我并不完全理解如何将基类与模板派生类一起使用的所有细节。这回答了我的问题。 - Bruno Hendrickx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接