Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what's the "struct hack" and "type/non-type hiding"?

Tags:

c++

I saw this in cppreference.

Lookup for a name in a scope finds all declarations of that name, with one exception, known as the "struct hack" or "type/non-type hiding": Within the same scope, some occurrences of a name may refer to a declaration of a class/struct/union/enum that is not a typedef, while all other occurrences of the same name either all refer to the same variable, non-static data member (since C++14), or enumerator, or they all refer to possibly overloaded function or function template names

The link to the above text is here

I don't understand what is "struct hack" and "type/non-type hiding".

Are they the same concept? Can you give a simple explanation? It would be nice to have a snippet demonstration.

like image 367
David Avatar asked Sep 10 '19 07:09

David


Video Answer


2 Answers

In the beginning, there was C. In C, declarations like these are entirely possible (and indeed frequent):

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

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

This code is totally normal in C because tags like tm or stat do not designate types. Only struct tm and struct stat do.

#include <time.h> 
tm my_time; // doesn't work in C

Enter C++. In C++, if you define struct tm { ... }; then tm alone is a type name.

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

But without the "one exception" detailed in your quote, C code like above would not compile with a C++ compiler.

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

Since breaking perfectly good C code is not an intention of C++, the exception was invented and put in place. It basically says that you are allowed to define variables, functions, ans some other stuff with the same name as a class/struct/union tag. If you do, then the tag alone stops being a type name in this scope.

#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

So this is the "type/non-type hiding" (because a type is hidden by a non-type)" hack. It's called a hack because it is a slight bend in an otherwise perfectly smooth and boring rule ("every name refers to one thing and one thing only"), which allows something (compatibility with old C code) that would not be possible without. Normal scope-based name hiding is not a hack. It is a perfectly regular thing, not a clever bend in anything.

like image 122
n. 1.8e9-where's-my-share m. Avatar answered Sep 24 '22 15:09

n. 1.8e9-where's-my-share m.


The sentence should really be understood as :

The exception concerning name look up concerns "struct hack" also named "type/non-type hiding".

So the definition of the concept you are looking for is really "type/non-type hiding".
The term "struct hack" can be confusing as it refers to the C flexible array which is a C specific implementation and not a name look up problem.

Concerning "type/non-type hiding" it is what allows you to write something like this and compile :

#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;
}

Show on godbolt.org

As you can see second::vector hides first::vector inside the scope of namespace second.

Moreover inside f function int vector hides second::vector.

The concept is well explained in an IBM thread :

If a class name or enumeration name is in scope and not hidden, it is visible. A class name or enumeration name can be hidden by an explicit declaration of that same name — as an object, function, or enumerator — in a nested declarative region or derived class. The class name or enumeration name is hidden wherever the object, function, or enumerator name is visible. This process is referred to as name hiding.

In a member function definition, the declaration of a local name hides the declaration of a member of the class with the same name. The declaration of a member in a derived class hides the declaration of a member of a base class of the same name.

You can also check the iso cpp standard:
6.3.10 Name hiding[basic.scope.hiding] or http://eel.is/c++draft/basic.scope.hiding

like image 41
PilouPili Avatar answered Sep 22 '22 15:09

PilouPili