在模板函数中使用未声明的变量合法吗?

时间:2015-04-09 14:51:22

标签: c++ templates

注意:原始问题大量使用宏,但此问题已简化。

问题

// header.hpp
template <typename T>
void foo()
{
   someBoolean = true ; // at this point "someBoolean" wasn't
}                       // declared

然后,它用于以下来源:

// source.cpp
#include "header.hpp"

static bool someBoolean = false ;

void bar()
{
   foo<char>() ; // here, we call/instantiate the function
}

在某些编译器(Windows,以前的Solaris)中,它可以工作。在当前支持C ++ 11的Solaris编译器中,它失败了,说someBoolean未定义。

根据标准,模板化代码是否可以使用一个变量(我们希望!)稍后在源中声明?

奖金问题

模板在一个标题中定义,该标题应包含在多个源中,每个源都有自己的布尔变量,并实例化模板。

预计在每个翻译单元中,模板会影响该翻译单元的静态布尔变量。

因此,预计每种模板在一种类型(例如“char”)上的实例化会影响不同的变量。

我们不是依赖于未定义的行为吗?

1 个答案:

答案 0 :(得分:24)

这与两阶段查找有关。简短版本是任何的名称取决于模板参数(如此处someBoolean)将在模板定义时查找。这意味着Solaris编译器在拒绝代码时是正确的。在定义模板之前尚未定义someBoolean

依赖于模板参数的名称(例如,如果您编写了类似T::someBoolean = true的内容)将被推迟到模板实例化时间 - 非常合理,因为它们的有效性无法确定,直到编译器知道T是什么。众所周知,MSVC没有正确地实现这些两阶段语义(至少在历史上),这就是你的代码在那里工作的原因。但是,这不是正确的C ++,也不是可移植的行为。

C ++标准(可能是草案)(未知版本)的第14.6节:

  

如果名称不依赖于模板参数(如14.6.2中所定义),则该名称的声明(或声明集)应在名称出现在模板定义中的范围内;该名称绑定到该点发现的声明(或声明),并且此绑定不受在实例化时可见的声明的影响。

(通过下面的@BenVoigt评论)