首先,一些上下文:我试图以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的新“extern模板”功能:
#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模板”不能在类声明中使用,我不能写
#include "pimpl_h.h"
class widget {
class impl;
extern template pimpl<impl>;
pimpl<impl> m;
// ...
};
我想不出任何其他方式.我的问题是:
IntelliSense是否错误,编译器是否接受我的代码?或者只是巧合,VC编译它并且它不是有效的C?
如果我的解决方案无效C,我有哪些替代方案?
最佳答案 我想我自己想出来了.在§14.7.2.11中,标准说
If an entity is the subject of both an explicit instantiation declaration and an explicit
instantiation definition in the same translation unit, the definition shall follow the
declaration.
这可能是IntelliSense所指的.这就是我注意到错误消息“…无法遵循显式实例化……”的地方.显然在任何地方都没有显式实例化,只是在widget的类定义中隐式实例化.所以我认为这是IntelliSense内部的一个错误.标准说,在同一段内
An entity that is the subject of an explicit instantiation declaration and that is also
used in a way that would otherwise cause an implicit instantiation (14.7.1) in the
translation unit shall be the subject of an explicit instantiation definition some-
where in the program; otherwise the program is ill-formed, no diagnostic required.
它不需要(潜在的)隐式实例化和显式实例化声明的任何特定顺序.
在这一点上,我也意识到我的解决方案对我原来的问题实际上是过度杀伤力.我不想阻止模板类声明和pimpl< impl>定义的隐式实例化,而只是阻止pimpl_impl.h中的模板类定义.外部模板pimpl< impl>压制两者,这解决了我的问题,但做的不仅仅是必要的.解决方案是声明pimpl的实际成员< impl>使用extern模板并稍后显式实例化它们.