模板中的类使用不完整
我很惊讶在各种采样版本的 g++ 上,以下编译没有错误或警告:
I am very surprised that on various sampled versions of g++, the following compiles without error or warning:
// Adapted from boost::checked_delete()
template <class T> inline void assert_complete()
{
typedef char type_must_be_complete[ sizeof(T) ? 1 : -1 ];
(void) sizeof(type_must_be_complete);
}
class X;
void f()
{
assert_complete<X>();
}
class X {};
int main() {}
如果 X
的定义缺失或在不同的翻译单元中,我会得到错误.
If the definition of X
is missing or in a different translation unit, I do get errors.
但是在上面的程序中,f
的定义不是我模板的单个实例化点吗?在那个实例化点 X
的不完整性难道不是语义错误吗?
But in the program as above, isn't the definition of f
the single instantiation point of my template? And isn't the incompleteness of X
at that instantiation point a semantic error?
(C++03 和/或 C++11 草案)标准是否称此程序为格式良好、格式错误、格式错误但不需要诊断或未定义的行为?
Does the (C++03 and/or C++11 Draft) Standard call this program well-formed, ill-formed, ill-formed but diagnostic not required, or undefined behavior?
@David Rodriguez - dribeas 报告说,clang++、comeau 和 Visual Studio 2010 也接受类似的代码.
@David Rodriguez - dribeas reports that clang++, comeau, and Visual Studio 2010 also accept similar code.
推荐答案
(我一直在等 Alf Steinbach 发布答案,但由于他不这样做,我将发布他在 Lounge C++ chat 中提到的参考):
(I was waiting to Alf Steinbach to post an answer, but since he is not doing it, I will post the reference that he mentioned in the Lounge C++ chat):
标准表明模板实例化在翻译单元已经翻译之后执行,因此及时,模板实例化发生在所有非模板化元素已经被处理.这在第 2.2 部分翻译阶段中进行了描述:
The standard indicates that template instantiations are performed after the translation unit has already been translated, so that in time, template instantiations happen after all the non templated elements have already been processed. This is described in section 2.2 Phases of translation:
第 1-6 段定义了预处理器的工作和基本的文本操作(字符集的转换、文字的连接......)
Paragraphs 1-6 define the preprocessor work and basic textual operations (conversions of the character set, concatenation of literals...)
7/分隔标记的空白字符不再重要.每个预处理令牌都被转换为一个令牌.(2.7).生成的标记在句法和语义上进行分析并作为翻译单元进行翻译.
7/ White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. (2.7). The resulting tokens are syntactically and semantically analyzed and translated as a translation unit.
8/翻译的翻译单元和实例化单元的组合如下:检查每个翻译的翻译单元以生成所需实例化的列表.找到所需模板的定义.是否需要包含这些定义的翻译单元的源是实现定义的.执行所有必需的实例化以生成实例化单元.[ 注意:这些类似于翻译的翻译单元,但不包含对未实例化模板的引用,也没有模板定义.― end note ] 如果任何实例化失败,程序就是格式错误的.
8/ Translated translation units and instantiation units are combined as follows: Each translated translation unit is examined to produce a list of required instantiations. The definitions of the required templates are located. It is implementation-defined whether the source of the translation units containing these definitions is required to be available. All the required instantiations are performed to produce instantiation units. [ Note: These are similar to translated translation units, but contain no references to uninstantiated templates and no template definitions. ― end note ] The program is ill-formed if any instantiation fails.
为简洁起见,我删除了一些注释.现在重要的一点似乎是在一步中转换代码而不触发模板实例化,然后在后面的步骤中实例化模板.这反过来意味着,如果类型在翻译单元中的任何位置完整,那么在编译器进行实例化时它就会被处理.
I have removed some of the notes for brevity. Now the important bit seems to be that the code is translated without triggering template instantiations in one step, and then in a later step the templates are instantiated. This in turn means that if the type is complete anywhere in the translation unit, it will have been processed by the time the compiler gets to the instantiation.
免责声明:对于我尝试过的所有编译器都表现出完全相同的行为(gcc、clang、comeau、VS 2010),这似乎是一个很好的理由,但这仅说明了当及时执行实例化时,它没有明确声明类型在模板实例化点可能是不完整的.
Disclaimer: This seems like a good reason for all of the compilers that I have tried showing the exact same behavior (gcc, clang, comeau, VS 2010), but this only states when in time the instantiation is performed, it does not explicitly state that the type can be incomplete at the point of instantiation of the template.
相关文章