Что такое "структура взлома" и "сокрытие типа/не-типа"?

Я видел это в cppreference.

Поиск по имени в области находит все объявления этого имени, за одним исключением, известным как "взлом структуры" или "сокрытие типа/не-типа": в одной и той же области некоторые вхождения имени могут ссылаться на объявление class/struct/union/enum, который не является typedef, в то время как все другие вхождения с одинаковыми именами либо ссылаются на одну и ту же переменную, нестатический член данных (начиная с С++ 14), либо перечислитель, либо все они ссылаются на возможно перегружены имена функций или шаблонов функций

Ссылка на текст выше здесь

Я не понимаю, что такое "структура взломать" и "сокрытие типа/не тип".

Это одна и та же концепция? Можете ли вы дать простое объяснение? Было бы неплохо иметь демонстрацию фрагмента.

Ответы

Ответ 1

В начале был C. В C подобные объявления вполне возможны (и действительно часты):

#include <time.h>  // defines struct tm { ... }
struct tm tm;

int stat(const char *pathname, struct stat *statbuf); // defined somewhere in POSIX headers

Этот код является полностью нормальным в C, потому что теги типа tm или stat не обозначают типы. Только struct tm и struct stat делают.

#include <time.h> 
tm my_time; // does not work in C

Введите C++. В C++, если вы определите struct tm { ... };, тогда tm - это имя типа.

#include <time.h>
tm my_time; // OK in C++

Но без "одного исключения", описанного в вашей цитате, код C, подобный приведенному выше, не будет компилироваться с помощью компилятора C++.

#include <time.h>
struct tm tm; // would not compile without the exception 
              // because tm alone already refers to a type
              // defined in this scope

Поскольку нарушать совершенно хороший C-код не является целью C++, исключение было изобретено и введено в действие. В основном это говорит о том, что вам разрешено определять переменные, функции и некоторые другие вещи с тем же именем, что и тег class/struct/union. Если вы это сделаете, то один только тег перестает быть именем типа в этой области.

#include <time.h>
struct tm tm;      // compiles because of the exception
tm my_time;        // no longer compiles because 'tm' variable hides the type
struct tm my_time; // OK

Так что это хак типа "сокрытие типа/нетипов" (потому что тип скрыт не типом) ". Он называется хаком, потому что это небольшой изгиб в совершенно гладком и скучном правиле (" каждое имя относится к одной вещи и только к одной "), что допускает что-то (совместимость со старым кодом C), без которого было бы невозможно. Обычное скрытие имени на основе области действия - это не хак. Это совершенно обычная вещь, а не умный изгиб во всем.

Ответ 2

Предложение действительно следует понимать как:

Исключение, касающееся поиска имен, также относится к "struct hack" с именем "скрытие типа/не типа".

Таким образом, определение концепции, которую вы ищете, на самом деле "скрывает тип/не тип".
Термин "взлом структуры" может сбивать с толку, поскольку он относится к гибкому массиву C, который является специфической реализацией C, а не проблемой поиска имени.

Что касается "сокрытия типа/не-типа", это то, что позволяет вам написать что-то вроде этого и скомпилировать:

#include <iostream>

namespace first
{
class vector
{
    public:
    int hidden;
};
}

namespace second {
  using namespace first;
  class vector
  {
      public:
      int visible;
  };
  double f()
  {
      vector f;
      f.visible=2;
      int vector = f.visible;
      return vector;
  }
};

int main() {
  std::cout << second::f() << std::endl;
}

Показать на godbolt.org

Как видите, second::vector скрывает first::vector внутри области видимости namespace second.

Кроме того, внутри f функция int vector скрывает second::vector.

Концепция хорошо объяснена в ветке IBM :

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

В определении функции-члена скрывается объявление локального имени. объявление члена класса с тем же именем. Объявление члена в производном классе скрывает объявление член базового класса с тем же именем.

Вы также можете проверить стандарт iso cpp:
6.3.10 Сокрытие имени [basic.scope.hiding] или http://eel.is/c++draft/basic.scope.hiding