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

Оператор sizeof предпочитает объект по типу?

#include <iostream> 

int C; 

class C { 
  private: 
    int i[2]; 
  public: 
    static int f() { 
        return sizeof(C); 
    } 
}; 

int f() 
{ 
    return sizeof(C); // why the C can't be the class type C.
} 

int main() 
{ 
   std::cout << "C::f() = " <<C::f() << "," 
             << " ::f() = " <<::f() << std::endl; 
} 

Вышеприведенный код возвращает: C::f() = 8, ::f() = 4

Мой вопрос в том, почему идентификатор C внутри глобальной функции f разрешает объект типа int, который имеет имя C, а не тип класса C? Имеет ли sizeof определенное правило поиска имен?

Заключение. Из того, что я читал в этом qaru.site/info/12876/..., скрытие имен классов по именам функций/объектов/перечислений относится к проблемам совместимости с C. И чтобы избежать этого непреднамеренного скрытия, нужно typedef класс принудительно выполнить ошибки компилятора.

4b9b3361

Ответ 1

sizeof не является ключом к этому вопросу. Это просто то, что может использоваться как для имени типа, так и для имени переменной. Эти правила применяются и к другим применениям идентификаторов.

§9.1 [class.name] (стандартный проект С++ n3797):

  1. ... snip... Если имя класса объявлено в области, где также объявлена ​​переменная, функция или перечислитель с тем же именем, тогда, когда оба объявления находятся в области видимости, класс может быть отнесен только к используя спецификатор специфицированного типа.

Существует класс по имени C и переменная с тем же именем в глобальной области. Поэтому класс можно ссылаться только с использованием специфицированного спецификатора типа (class C).

Внутри определения C, однако, первая часть этого параграфа имеет значение:

§9.1 [class.name]:

  1. Объявление класса вводит имя класса в область, где оно объявлено, и скрывает любой класс, переменную, функцию или другое объявление этого имени в охватывающей области... snip...

§9 [класс]:

  1. ... snip... Имя класса также вставляется в область самого класса; это известно как имя введенного класса... snip...

Итак, внутри области class C имя введенного класса скрывает объявление int C из внешней области. Поэтому вы можете ссылаться на C без уточненного спецификатора типа. Чтобы обратиться к глобальному int C, вы можете использовать ::C

Ответ 2

Что касается вашего вопроса, sizeof не имеет специальных правил синтаксического анализа или оценки.

Рассмотрим следующее:

#include <iostream>
#include <typeinfo>

int C; 

class C { 
public:
    int i[2]; 
}; 

int main() 
{ 
   // compiles fine:
   int x = C;

   // prints 0:
   std::cout << C << "\n";

   // prints something that corresponds to "int"
   // (or even "int" itself):
   std::cout << typeid(C).name() << "\n";
}

Во всех трех случаях C берется как переменная int, а не как имя типа.

Если вам нужно четкое различие, вы всегда можете использовать class C:

#include <iostream>
#include <typeinfo>

int C; 

class C { 
public:
    int i[2]; 
}; 

int main() 
{ 
   // prints something that corresponds to "class C"
   // (or even "class C" itself):
   std::cout << typeid(class C).name() << "\n";

   // prints sizeof(int):
   std::cout << sizeof(C) << "\n";

   // prints sizeof(int) * 2:
   std::cout << sizeof(class C) << "\n";
} 

Ответ 3

Попытка скомпилировать этот код даст вам ответ

#include <iostream>

int C;

class C {
    int i[2];
  public: 
    static int f() { 
        return sizeof(C); 
    }
}; 

int f() { 
    return sizeof(C); // why the C can't be the class type C.
} 

int main() {
   C a; // <-- Adding this line generates the error
   std::cout << "C::f() = " <<C::f() << "," 
             << " ::f() = " <<f() << std::endl; 
} 

prog.cpp:22:4: error: must use 'class' tag to refer to type 'C' in this scope
   C a;
   ^
   class 
prog.cpp:3:5: note: class 'C' is hidden by a non-type declaration of 'C' here
int C; 
    ^
1 error generated.

Компилятор:

clang version 3.7.0 (tags/RELEASE_370/final 246979)
Target: x86_64-unknown-linux-gnu
Thread model: posix

Чтобы получить правильный вывод:

int f() { 
    return sizeof(class C);
}