如何将"extern template"与同一类中的模板成员使用的嵌套类一起使用?

How to use "extern template" with a nested class which is used by a templated member in the same class?

本文关键字:一起 成员 嵌套 template extern 一类      更新时间:2023-10-16

首先,一些上下文:我试图以Herb Sutter在GotW#101的解决方案中提出的方式使用Pimpl习语。这在头文件中看起来像这样:

#include "pimpl_h.h"
class widget {
    class impl;
    pimpl<impl> m;
    // ...
};

实现方式如下:

#include "pimpl_impl.h"
class widget::impl {
    // ...
};

当一个使用这种技术的类使用另一个Pimpl类进行自己的实现时,我试图解决的问题就出现了。它包括"pimpl_impl.h",因此编译器(在我的例子中是VC++2013)获得了另一个类的pimpl <impl>的具体模板的知识,并试图隐式实例化它,这当然会导致编译错误,因为它不知道该类的实现。

为了解决这个问题,我在标题中使用了C++11的新"外部模板"功能:

#include "pimpl_h.h"
class widget {
    class impl;
    pimpl<impl> m;
    // ...
};
extern template pimpl<widget::impl>;

这应该保证只有我在提供widget::impl实现的编译单元中的显式实例化才能导致实际的实例化。这编译起来没有问题,但IntelliSense显示了一个错误:

Error: 'extern template' cannot follow explicit instantiation of class "pimpl<widget::impl>"

由于"extern template"不能在类声明中使用,我无法编写

#include "pimpl_h.h"
class widget {
    class impl;
    extern template pimpl<impl>;
    pimpl<impl> m;
    // ...
};

我想不出其他办法了。我的问题是:

IntelliSense接受我的代码是错误的,编译器是正确的吗?或者只是巧合,VC++编译了这个,而它不是有效的C++?

如果我的解决方案不是有效的C++,我有什么替代方案?

我想这是我自己想出来的。在§14.7.2.11中,标准规定

如果一个实体是显式实例化声明和显式实例化的主体实例化定义在同一翻译单元中,定义应遵循公告

这可能就是IntelliSense所指的。这就是我注意到错误消息说"…不能遵循显式实例化…"的地方。显然,任何地方都没有显式实例化,只有widget的类定义中的隐式

一个实体,它是显式实例化声明的主体,也是使用的方式会导致翻译单位应该是一个明确的实例化定义的主题-程序中的位置;否则程序格式不正确,不需要进行诊断。

其不需要(潜在的)隐式实例化和显式实例化声明的任何特定顺序。

在这一点上,我也意识到我的解决方案实际上对我最初的问题来说是过度的。我不想阻止pimpl<impl>的模板类声明定义的隐式实例化,而只是pimpl_impl.h中的模板类

定义extern template pimpl<impl>抑制了两者,这解决了我的问题,但做得更多。解决方案是用extern template声明pimpl<impl>的实际成员,然后显式实例化它们。