#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 конкретное правило поиска имени?

Заключение : из того, что я прочитал в этом https://stackoverflow.com/a/612476/1021388, скрытие имен классов по именам функций / объектов / перечислителей необходимо для проблем совместимости с C. И чтобы избежать этого непреднамеренного сокрытия, следует typedef класс вызывать ошибки компилятора.

13
Rich 26 Окт 2015 в 18:49

3 ответа

Лучший ответ

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

§9.1 [class.name] (стандартный черновик c ++ n3797):

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

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

Однако внутри определения C важна первая часть этого абзаца:

§9.1 [имя_класса]:

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

§9 [класс]:

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

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

20
eerorika 26 Окт 2015 в 17:03

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

#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);
} 
1
smac89 26 Окт 2015 в 16:30

Что касается вашего вопроса, 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
Christian Hackl 26 Окт 2015 в 16:10