2011-12-29 3 views
9

Это самый простой пример, который я мог бы придумать, чтобы воспроизвести проблему.Неопределенная ссылка на статическую локальную переменную

template<class T> 
struct X 
{ 
    static void foo() 
    { 
     static int z = 0; 
     []{ z = 1; }(); 
    } 
}; 

int main() 
{ 
    X<int>::foo(); 
    return 0; 
} 

Я пробовал с MinGW 4.6 и 4.7, а также г ++ 4.6 в Ubuntu и все они дают мне ошибки ссылку «неопределенная ссылка на` г '». Итак, теперь это заставляет меня задаться вопросом, является ли это даже законным. У VC10 нет проблем с этим.

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

+0

Добавить C++ 11 tag, может быть, это даст вам лучший ответ – marcinj

ответ

10

г ++ принимает следующее, но VC++ не делает:

[&z]{ z = 1; }(); 

Здесь z настоящее время захвачены так г ++ не жалуется на неопределенной ссылки. Однако:

5.1.2/10:

Идентификаторы в списке захвата-искомыми используя обычные правила для неквалифицированного поиск имен (3.4.1); каждый такой поиск должен найти переменную с автоматическим временем хранения, объявленным в области охвата локального выражения лямбда .

z является не автоматического хранения. z не может быть захвачен. Поэтому поведение g ++ является неправильным, а VC++ является правильным.

В своем коде, что VC++ принимает и г ++ не делает:

[]{ z = 1; }(); 

z получает доступ VC++ как статическое хранилище, которое допускается в лямбда тела. g ++, по-видимому, не разрешает имя z статической переменной, объявленной выше, и поэтому выдает undefined reference, в то время как это не должно.

Т.Л., д-р Это, вероятно, ошибка в г ++

Edit: It is indeed a bug и фиксируется в 4.7.

+0

Ницца: он может даже объяснить, почему работа TonyK действительно работает, хотя я не уверен, будет ли «ссылка на z» иметь автоматическое хранилище. Смотря вверх 5.2.1/9, также следует отметить, что «область охвата» вашей заметки относится к остановкам в самой внутренней закрывающей функции, что также исключает «глобалы» (которые в любом случае не имеют автоматической продолжительности хранения).Поэтому, кажется, полностью предполагается, что в списке захвата можно копировать только локальные переменные. –

-1

Я не понимаю, почему он работает для обычных классов, а не для шаблонов. Но вы можете получить ваш пример будет работать, если вы захватить локальную переменную z по ссылке:

static void foo() 
{ 
    static int z = 0; 
    [&z]{ z = 1; }(); // Note: [&z] 
} 

В Википедии есть больше информации here.

+0

Кто-то по имени @cicada отправил тот же ответ, но потом удалил его (теперь вы здесь с таким же ответом), не знаю, почему она удалила его 0_o –

+0

@ Mr.Anubis, потому что я все еще пытаюсь понять, почему g ++ ведет себя иначе, чем VC++ –

+0

@Cicada. Оба компилятора могут вести себя по-разному, когда есть ошибка, а другая нет. –

Смежные вопросы