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

Понимание запутанной грамматики typedef

Рассмотрим следующий фрагмент кода

typedef int type;
int main()
{
   type *type; // why is it allowed?
   type *k ;// which type?
}

Я получаю сообщение об ошибке 'k' is not declared in this scope. Компилятор анализирует type *k как умножение между type* и k. Разве эта грамматика не очень запутанна?

Почему type *type разрешен стандартом С++? Потому что грамматика так говорит? Почему?

4b9b3361

Ответ 1

Вопрос в том, когда именно имя переменной определяется как идентификатор, и язык определяет, что он сразу после точки в коде, где объявлена ​​переменная:

typedef int type;
int main() {
   type t;   // type refers to ::type
   int       // type still refers to ::type
   type;     // variable declared, this shadows ::type
   type + 1; // type is a variable of type int.
}

В других контекстах существуют аналогичные правила, и это просто вопрос принятия идентификаторов. Существуют и другие подобные ситуации, например, в списке инициализации класса:

struct test {
   int x;          // declare member
   test( int x )   // declare parameter (shadows member)
   : x(            // refers to member (parameter is not legal here)
        x )        // refers to parameter
   {};
};

Или в области идентификаторов в определении функций-членов:

struct test {
   typedef int type;
   type f( type );
};
test::type         // qualification required, the scope of the return type is
                   // at namespace level
test::f(
         type t )  // but the scope of arguments is the class, no qualification
                   // required.
{}

С точки зрения обоснования решения я не могу вам сказать, но он последователен и прост.

Ответ 2

type *type; // why is it allowed?

С++ 11 3.3.2/1 говорит:

Точка объявления для имени сразу после его полного объявления (раздел 8) и перед его инициализатором (если есть)

Таким образом, имя переменной type не вводится до тех пор, пока не будет использовано имя типа type; имя типа является единственным доступным значением type во время декларатора.

type *k ;// which type?

Локальное имя переменной скрывает глобальное имя типа, поэтому оно выбрано здесь. Это описано в С++ 11 3.3.10/1:

Имя может быть скрыто явным объявлением того же имени во вложенной декларативной области или производном классе.

Конечно, все еще доступно полное имя типа ::type.

Ответ 3

Это запутанно, но это единственный способ получить доступ к переменной type. Если вы хотите использовать тип type, вы можете сделать:

typedef int type;
int main() {
    type *type;
    ::type *k ;
    return 0;
} 

Большинство этих грамматических монстров происходят из обратной совместимости с C.

Ответ 4

Обоснование сохранения пространств имен (а не в смысле С++, но в пространстве имен переменных/типов) совершенно очевидно: если вы не загрязняете пространство имен переменных именами типов, меньшее количество разрывов кода на typedef.

Предположим, что существовал ранее существовавший код с переменной с именем "employee". Если переменные и typedefs жили в одном и том же пространстве имен, "typedef struct {} employee;" будет нарушать существующий код, требуя изменения имени переменной (что было больше проблемой в дни, предшествующие IDE). Однако, если они не разделяют пространство имен, проблем нет, и у людей возникает одна проблема, о которой стоит беспокоиться при выборе имен типов в больших базовых кодах.

Ответ 5

Я думаю, что это допустимо, вероятно, потому, что он обеспечивает гибкость для программистов при выборе имени для переменных, которые они объявляют. В С# вы можете объявить свойство с тем же именем, что и тип:

//C# code
class Manager
{
   public Name Name {get;set;}
};

Когда я код на С#, я считаю эту функцию очень полезной. Потому что у меня больше вариантов выбора имен. В противном случае, если у меня есть тип, называемый Name, тогда я бы не смог создать свойство с тем же именем, я был бы вынужден выбрать другое имя, например Name_, _Name, Name, Name и т.д. - все это не нравится мне.


Что касается вашего кода, поскольку в области (после объявления объекта type), type уже является переменной, тип type не может быть передан напрямую. Но я думаю, что это должно составить штраф и в соответствии со стандартом:

typedef int type;
int main()
{
   type *type; // why is it allowed?
   ::type *k ;// which type?
}

Демо: http://ideone.com/chOov