首先,一些背景:我试图以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 ++,我还有哪些替代方案?
答案 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
的实际成员,并在以后显式实例化它们。