注意:原始问题大量使用宏,但已针对此问题进行了简化.
// header.hpp
template <typename T>
void foo()
{
someBoolean = true ; // at this point "someBoolean" wasn't
} // declared
Run Code Online (Sandbox Code Playgroud)
然后,它用于以下来源:
// source.cpp
#include "header.hpp"
static bool someBoolean = false ;
void bar()
{
foo<char>() ; // here, we call/instantiate the function
}
Run Code Online (Sandbox Code Playgroud)
在某些编译器(Windows,以前的Solaris)中,它可以工作.在当前支持C++ 11的Solaris编译器中,它失败了,说someBoolean未定义.
根据标准,模板化代码是否可以使用一个变量(我们希望!)稍后在源代码中声明?
模板在一个标题中定义,该标题应包含在多个源中,每个源都有自己的布尔变量,并实例化模板.
预计在每个翻译单元中,模板会影响该翻译单元的静态布尔变量.
因此,预期一种类型(例如"char")上的模板的每个实例化都会影响不同的变量.
我们不是依赖于未定义的行为吗?
CAd*_*ker 24
这与两阶段查找有关.简短版本是任何不依赖于模板参数的名称(如此someBoolean处)将在模板定义时查找.这意味着Solaris编译器在拒绝代码时是正确的.someBoolean在定义模板之前尚未定义.
依赖于模板参数的名称(例如,如果你写过类似的东西T::someBoolean = true)将被推迟到模板实例化时间 - 非常合理,因为在编译器知道什么T是有效之前无法确定它们的有效性.众所周知,MSVC没有正确地实现这些两阶段语义(至少在历史上),这就是你的代码在那里工作的原因.但它不是正确的C++而不是可移植的行为.
C++标准(可能是草案)的(未知版本)的14.6节:
如果名称不依赖于模板参数(如14.6.2中所定义),则该名称的声明(或声明集)应在名称出现在模板定义中的范围内; 该名称绑定到在该点找到的声明(或声明),并且此绑定不受在实例化时可见的声明的影响.
(通过下面的@BenVoigt评论)