如何使用“外部模板”有一个嵌套类,由同一类中的模板成员使用? [英] How to use "extern template" with a nested class which is used by a templated member in the same class?

查看:194
本文介绍了如何使用“外部模板”有一个嵌套类,由同一类中的模板成员使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,一些上下文:我试图以Herb Sutter在他的 GotW#101 。在头文件中看起来像这样:

  #includepimpl_h.h
class widget {
class impl;
pimpl< impl> m;
// ...
};

实现方式如下:

  #includepimpl_impl.h
class widget :: impl {
// ...
};

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



为了解决这个问题,我使用了新的extern模板功能:

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

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

 错误:'extern template'不能跟随显式实例化类 pimpl< widget :: impl> 

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

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

我不能想到任何其他方式。我的问题是:



IntelliSense是否错误,编译器接受我的代码?



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

解决方案

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


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


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


一个实体,它是明确的实例化声明的主体,也是
以另一种方式导致
翻译单元中的隐式实例化(14.7.1)将是程序中的显式实例化定义some-
的主题;


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



在这一点上,我还意识到我的解决方案实际上是对我的原始问题overkill。我不想阻止 pimpl< impl> 的模板类声明定义但只有 pimpl_impl.h 中的模板类定义 extern模板pimpl< impl> 抑制了这两个,这解决了我的问题,但超过必要。解决方案是用 extern template 声明 pimpl< impl> 的实际成员并稍后显式实例化。 p>

First, some context: I'm trying to use the Pimpl idiom in the way Herb Sutter presented it in the solution to his GotW #101. This would look like this in the header file:

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

The implementation would look like this:

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

The problem I am trying to solve appears when a class using this technique uses another Pimpl class for their own implementation. It includes the "pimpl_impl.h", so the compiler (in my case VC++ 2013) gains knowledge of the concrete template for pimpl <impl> of the other class and tries to implicitly instantiate it, which of course results in compilation errors as it does not know about the implementation of that class.

To solve this, I have used the new "extern template" feature of C++ 11 in the header:

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

This should guarantee that only the explicit instantiation I have in the compilation unit providing the implementation of widget::impl leads to an actual instantiation. This compiles without a problem, but IntelliSense shows me an error:

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

As "extern template" cannot be used inside of a class declaration, I cannot write

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

and I can't think of any other way. My question is:

Is IntelliSense wrong and the compiler right in accepting my code? Or is it just coincidence that VC++ compiles this and it isn't valid C++?

If my solution is not valid C++, what alternatives do I have?

解决方案

I think I figured this out myself. In §14.7.2.11 the standard says

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.

which is probably what IntelliSense refers to. And this is where I noticed that the error message says "...cannot follow explicit instantiation...". There is obviously no explicit instantiation anywhere, just an implicit instantiation inside the class definition of widget. So I assume that this is a bug inside IntelliSense. Inside the same paragraph, the standard says

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.

which does not require any specific order of (potential) implicit instantiation and explicit instantiation declaration.

At this point I also realized that my solution is actually overkill for my original problem. I did not want to prevent the implicit instantiation of both the template class declaration and definition of pimpl<impl>, but only the template class definition inside pimpl_impl.h. The extern template pimpl<impl> suppressed both, which solved my problem but does more than necessary. The solution is to declare the actual members of pimpl<impl> with extern template and explicitly instantiate them later.

这篇关于如何使用“外部模板”有一个嵌套类,由同一类中的模板成员使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆