Подтвердить что ты не робот

Использует необъявленную переменную legal в функции шаблона?

Примечание. Исходная проблема сильно использует макросы, но для этого вопроса была упрощена.

Вопрос

// 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) он работает. И в текущем компиляторе Solaris, поддерживающем С++ 11, он терпит неудачу, говоря, что someBoolean - это undefined.

В соответствии со стандартом, может ли шаблонный код использовать переменную, которая будет (мы надеемся!) объявлена ​​позже в источнике?

Бонусный вопрос

Шаблон определен в заголовке, который, как ожидается, будет включен в несколько источников, каждый из которых имеет свою собственную логическую переменную и создает экземпляр шаблона.

Ожидалось, что в каждой единицы перевода шаблон повлияет на статическую булевую переменную этой единицы перевода.

Каждое создание шаблона на одном типе (скажем, "char" ), как ожидается, повлияет на разные переменные.

Не полагаемся ли мы на поведение undefined?

4b9b3361

Ответ 1

Это связано с двухфазным поиском. Краткая версия заключается в том, что любые имена, которые не зависят от параметра шаблона (например, someBoolean здесь), будут проверяться на время определения шаблона. Это означает, что компилятор Solaris правильно отклоняет код. someBoolean не был определен до того, как будет определен шаблон.

Имена, которые зависят от параметра шаблона (например, если вы написали что-то вроде T::someBoolean = true), будут отложены до времени создания шаблона - очень разумно, так как их достоверность не может быть определена до тех пор, пока компилятор не узнает, что T является. Известно, что MSVC не выполняет эту двухфазную семантику должным образом (по крайней мере исторически), поэтому ваш код работает там. Это не правильно С++, а не переносимое поведение.

Раздел 14.6 (неизвестная версия) стандарта С++ (вероятно, черновик):

Если имя не зависит от параметра шаблона (как определено в 14.6.2), объявление (или набор объявлений) для этого имени должно быть в области видимости в точке, где имя отображается в определении шаблона; имя привязано к объявлению (или объявлениям), найденному в этой точке, и эта привязка не является показателем деклараций, которые видны в момент создания экземпляра.

(через комментарий @BenVoigt ниже)