поиск имени для typedef глючит в компиляторе GNU?

Следующий код

#include <iostream>

typedef double A; // a global typedef

template <class Z> struct B // a template class...
{
    A i{22.2}; // global typedef is in scope
    typedef int A; // now  a local typedef with the same name is introduced
    A b{24};  // now the local typedef is in scope
    Z c{36}; // a simple member of the template type
};

template <class Z> struct C : B<Z> // a template struct inheriting B
{
    A a;  // global typedef is in scope because we are in a template struct
    C(  ) : a(2.2){  }
};

int main(  )
{
    C<int> c;
    std::cout << "c's members: "
           << c.a << ' '
           << c.i << ' '
           << c.b << ' '
           << c.c << std::endl;
    std::cout << "their sizeof: "
           << sizeof(c.a) << ' ' 
           << sizeof(c.i) << ' '
           << sizeof(c.b) << ' '
           << sizeof(c.c) <<  std::endl;
}

НЕ скомпилирован GNU-g++ 4.9.2, а clang 3.5.0 и ведет себя так, как я пытался объяснить во встроенных комментариях, и как это видно из полученного вывода. Это ошибка в компиляторе GNU? Диагностика говорит, что строка typedef int A; в области struct B

ошибка: изменяет значение «A» с «typedef double A»

Обратите внимание, что когда иерархия не состоит из template (и, конечно, объявление Z c{36}; удалено), поиск, выполненный clang в области C (правильно, как я полагаю), находит typedef в области B и рассматривает член a быть типа int; то выдает предупреждение об сужении инициализирующей double константы 2.2...


person GSi    schedule 06.11.2015    source источник
comment
comment
Можете ли вы правильно отформатировать и сократить этот код?   -  person Columbo    schedule 06.11.2015
comment
Что за странное углубление?   -  person Lightness Races in Orbit    schedule 06.11.2015


Ответы (1)


Из стандартного проекта С++ (N4140)

§3.3.7 [basic.scope.class]

2) Имя N, используемое в классе S, должно ссылаться на одно и то же объявление в его контексте и при повторной оценке в завершенной области действия S. Для нарушения этого правила диагностика не требуется.

A i{22.2} изначально относится к глобальному ::A. Но после объявления B::A при повторной оценке в завершенной области действия B оно будет ссылаться на B::A. Это нарушает правило выше.

Чтобы это исправить, используйте полное имя: ::A i{22.2}. ::A всегда ссылается на глобальный A даже после объявления B::A, так что это не нарушает правило.

Это не ошибка в g++; это просто плохо сформированная программа. Компилятор не обязан не давать вам диагностику на нарушение правила, но и не обязан его принимать.

person eerorika    schedule 06.11.2015