它是否对C ++编译器隐式实例化模板类的所有成员函数有效? [英] Is it valid for a C++ compiler to implicitly instantiate ALL member functions of a template class?
问题描述
假设我有一个公共类和一个私有实现类(例如PIMPL模式),并且希望用一个带有选中删除的模板智能指针类来包装私有类,如下所示:
Suppose I have a public class and a private implementation class (e.g. PIMPL pattern), and I wish to wrap the private class with a template smart pointer class with a checked delete, as follows:
PublicClass.h
PublicClass.h
class PrivateClass;
// simple smart pointer with checked delete
template<class X> class demo_ptr
{
public:
demo_ptr (X* p) : the_p(p) { }
~demo_ptr () {
// from boost::checked_delete: don't allow compilation of incomplete type
typedef char type_must_be_complete[ sizeof(X)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete the_p;
}
private:
X* the_p;
};
// public-facing class that wishes to wrap some private implementation guts
class PublicClass
{
public:
PublicClass();
~PublicClass();
private:
demo_ptr<PrivateClass> pvt;
};
PublicClass.cpp
strong>
#include "PublicClass.h"
class PrivateClass
{
public:
// implementation stuff goes here...
PrivateClass() {}
};
//---------------------------------------------------------------------------
PublicClass::PublicClass() : pvt(new PrivateClass()) {}
PublicClass::~PublicClass() {}
main.cpp
main.cpp
#include "PublicClass.h"
int main()
{
PublicClass *test = new PublicClass();
delete test;
return 0;
}
此代码在Visual C ++ 2008上成功编译,但无法在旧版本的C ++ Builder。特别是 main.cpp
不能编译,因为 demo_ptr< PrivateClass> ::〜demo_ptr
c $ c> main.cpp ,并且析构函数不能编译,因为它不能对<$ c不完整的类型做 sizeof
$ c> PrivateClass 。显然,编译器在消费 main.cpp
中实例化〜demo_ptr
是没有用的,永远不能生成一个明智的实现(看看〜PrivateClass
是不可访问的)。 ( PublicClass.cpp
在所有测试的编译器上编译良好。)
This code compiles successfully on Visual C++ 2008, but fails to compile on an old version of C++ Builder. In particular, main.cpp
does not compile because demo_ptr<PrivateClass>::~demo_ptr
is being instantiated by main.cpp
, and that destructor won't compile because it can't do sizeof
on an incomplete type for PrivateClass
. Clearly, it is not useful for the compiler to be instantiating ~demo_ptr
in the consuming main.cpp
, since it will never be able to generate a sensible implementation (seeing as how ~PrivateClass
is not accessible). (PublicClass.cpp
compiles fine on all tested compilers.)
我的问题是:关于模板类的成员函数的隐式实例化?可能是以下之一?
My question is: what does the C++ standard say about implicit instantiation of a template class's member functions? Might it be one of the following? In particular, has this changed over the years?
- 如果使用模板类,那么所有成员函数
- 或者:模板类函数只能在实际使用时一次隐式实例化一次。如果没有使用特定的模板类函数,那么它不应该被隐式实例化 - 即使其他模板类函数被使用和实例化。
看起来很清楚,第二种情况是今天,因为这个模式与PIMPL和 unique_ptr
一起使用,但也许这不是过去的情况?第一种情况是过去可接受的编译器行为吗?
It seems clear that the second case is the case today because this same pattern is used with PIMPL and unique_ptr
with its checked delete, but maybe that was not the case in the past? Was the first case acceptable compiler behavior in the past?
或者换句话说,是编译器bug,还是精确地遵循C ++ 98标准,
Or in other words, was the compiler buggy, or did it accurately follow the C++98 standard, and the standard changed over the years?
(有趣的是,如果你删除了C ++ Builder中的选中的删除,并且关闭了函数内联,项目将很乐意编译。 PublicClass.obj
将包含正确的〜demo_ptr
实现, main.obj
将包含一个不正确的〜demo_ptr
实现与未定义的行为。使用的函数将取决于这些文件被馈送到链接器的顺序。)
(Fun fact: if you remove the checked delete in C++ Builder, and have function inlining turned off, the project will happily compile. PublicClass.obj
will contain a correct ~demo_ptr
implementation, and main.obj
will contain an incorrect ~demo_ptr
implementation with undefined behavior. The function used will depend on the order in which these files are fed to the linker.)
更新:这是由于编译器错误,正如Andy Prowl所指出的,这在C ++ Builder XE8中仍然不是固定的。我已向Embarcadero报告错误: bcc32编译器在使用std ::时会导致未定义的行为auto_ptr with PIMPL idiom因为模板实例化规则不遵循C ++规范
推荐答案
使用模板类,那么该类的所有成员函数都应该被隐式实例化 - 是否使用?
If a template class is used, then all member functions of the class should be implicitly instantiated - whether used or not?
否,这绝对不是这样。根据C ++ 11标准(和C ++ 03标准的第14.7.1 / 9段)第14.7.1 / 10段非常清楚地规定:
No, this is definitely not the case. Per Paragraph 14.7.1/10 of the C++11 Standard (and Paragraph 14.7.1/9 of the C++03 Standard) very clearly specifies:
实现不应隐式实例化函数模板,成员模板,非虚拟
成员函数,成员类或类的静态数据成员
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation.
至于需要实例化时,第14.7.1 / 2段规定:
As for when instantiation is required, Paragraph 14.7.1/2 specifies:
除非类模板或成员模板的成员已被显式实例化或显式
专用化,否则成员的专门化将隐式实例化当在需要成员定义存在的上下文中将专业化引用为
时; [...]
如果从不引用成员函数,肯定不是这样。
This is certainly not the case if a member function is never referenced.
不幸的是,我不能提供关于C ++ 03之前的规则的官方参考,但据我所知,同样的lazy 实例化机制在C ++ 98中被采用。
Unfortunately, I can't provide an official reference on what the rules were before C++03, but to the best of my knowledge the same "lazy" instantiation mechanism was adopted in C++98.
这篇关于它是否对C ++编译器隐式实例化模板类的所有成员函数有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!