如何使用" extern模板"使用嵌套类,由同一个类中的模板化成员使用?

时间:2014-04-25 21:00:27

标签: c++ c++11 templates

首先,一些背景:我试图以Herb Sutter在他GotW #101的解决方案中呈现它的方式使用Pimpl习语。这在头文件中看起来像这样:

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

实现如下:

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

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

为了解决这个问题,我使用了新的&#34; extern模板&#34;标题中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>"

作为&#34; extern模板&#34;不能在类声明中使用,我不能写

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

我无法想到任何其他方式。我的问题是:

IntelliSense是否错误,编译器是否接受我的代码?或者VC ++编译它并且它不是有效的C ++只是巧合?

如果我的解决方案无效C ++,我还有哪些替代方案?

1 个答案:

答案 0 :(得分:2)

我想我自己想出来了。在§14.7.2.11中,标准说

  

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

这可能是IntelliSense所指的。这就是我注意到错误消息“...无法跟随显式实例化......”的地方。显然没有任何明确的实例化,只是widget的类定义中的隐式实例化。所以我认为这是IntelliSense内部的一个错误。在同一段内,标准说

  

作为显式实例化声明主题的实体,也是   以一种否则会导致隐式实例化(14.7.1)的方式使用   翻译单位应成为明确的实例化定义的主题 -   程序中的位置;否则程序结构不合理,无需诊断。

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

此时我也意识到我的解决方案实际上对我原来的问题来说太过分了。我不想阻止pimpl<impl>的模板类声明定义的隐式实例化,而只是模板类定义pimpl_impl.h内。 extern template pimpl<impl>抑制了两者,这解决了我的问题,但做的不仅仅是必要的。解决方案是使用pimpl<impl>声明extern template的实际成员,并在以后显式实例化它们。