13

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.

P.W
  • 26,289
  • 6
  • 39
  • 76
Guokas
  • 750
  • 7
  • 23

2 Answers2

7

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

PilouPili
  • 2,601
  • 2
  • 17
  • 31
  • Thanks for your useful answer !. I have to say that the essential issue still exists. As above you said **the concerns "struct hack" also named "type/non-type hiding"**. so what's the similarity between "struck hack" and "type/non-type"? – Guokas Sep 11 '19 at 02:25
  • I think we are hitting a semantic issue. struct hack in c++ is meant here as a totally different concept as struct hack in C99 which should really be called flexible arrays (see http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf). Also note that C++ does not have flexible array members. I really think that you could suggest to the website cpprefrence to delete the "struct hack" part. Moreover struct hack as a c++ feature is never mentionned in the iso cpp standard (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf). I have edited my answer to quote this paper. – PilouPili Sep 11 '19 at 07:27
  • 2
    Scopes and namespaces have nothing to do with the subject of the question. The type/non-type hiding refers to this sequence: `struct vector {}; int vector = 42;` where both definitions are **in the same scope**. – n. m. could be an AI Sep 11 '19 at 08:03
7

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • I get it, this is **C++** for compatibility with **C** code. And another thing is clear also that the referred declaration of **class/struct/union/enum** must not be a **typedef**. Is it because of **C** don't take part in with **typedef**? – Guokas Sep 12 '19 at 08:17
  • @V.Wu You cannot do it with typedef in C either. – n. m. could be an AI Sep 12 '19 at 09:05
  • this sentence "some occurrences of a name may refer to a declaration of a class/struct/union/enum that is not a typedef", the *declaration* cannot be *typedef*. is it because of *C* does not have *typedef*? – Guokas Sep 13 '19 at 01:53
  • No, C has typedef. – n. m. could be an AI Sep 13 '19 at 04:35