【问题标题】:what's the "struct hack" and "type/non-type hiding"?什么是“结构黑客”和“类型/非类型隐藏”?
【发布时间】:2019-09-10 07:23:13
【问题描述】:

我在 cppreference 中看到了这个。

在范围内查找名称会找到该名称的所有声明,但有一个例外,称为“结构破解”或“类型/非类型隐藏”:在同一范围内,某些名称的出现可能会引用到不是 typedefclass/struct/union/enum 的声明,而所有其他出现的相同名称要么都引用同一个变量、非静态数据成员(自 C++14 起)或枚举器,要么它们all 引用可能重载的函数或函数模板名称

以上文字的链接是here

我不明白什么是“结构破解”和“类型/非类型隐藏”。

它们是同一个概念吗?能给个简单的解释吗?最好有一个 sn-p 演示。

【问题讨论】:

    标签: c++


    【解决方案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 语言中是完全正常的,因为像tmstat 这样的标签 不指定类型。只有struct tmstruct stat 可以。

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

    输入 C++。在 C++ 中,如果您定义 struct tm { ... };,则 tm alone 是一个类型名称。

    #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++ 的本意,因此发明并实施了异常。它基本上说你可以定义变量、函数和其他一些与类/结构/联合标签同名的东西。如果你这样做了,那么标签本身就不再是这个范围内的类型名称。

    #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
    

    所以这就是“类型/非类型隐藏”(因为类型被非类型隐藏)”hack。它被称为 hack,因为它是对原本完全平滑和无聊的规则的轻微弯曲(“每个名称仅指一件事和一件事”),它允许一些事情(与旧 C 代码的兼容性),如果没有这些事情是不可能的。正常的基于范围的名称隐藏不是 hack。这是完全正常的事情,而不是任何巧妙的弯曲。

    【讨论】:

    • 我明白了,这是 C++ 用于兼容 C 代码。还有一点很清楚,class/struct/union/enum 的引用声明不能是 typedef。是不是因为C不参与typedef
    • @V.Wu 你也不能在 C 中使用 typedef。
    • 这句话“一些出现的名字可能指的不是typedef的类/结构/联合/枚举的声明”,声明不能是类型定义。是不是因为C没有typedef
    • 不,C 有 typedef。
    【解决方案2】:

    这句话真的应该理解为:

    关于名称查找的异常也与“struct hack”有关 命名为“类型/非类型隐藏”。

    因此,您正在寻找的概念的定义实际上是“类型/非类型隐藏”。
    术语“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;
    }
    

    Show on godbolt.org

    如您所见,second::vectorfirst::vector 隐藏在namespace second 的范围内。

    而且在f函数内部int vector隐藏second::vector

    IBM thread 中很好地解释了这个概念:

    如果类名或枚举名在作用域内且未隐藏,则为 可见的。类名或枚举名可以被显式隐藏 同名声明——作为对象、函数或枚举器 — 在嵌套的声明区域或派生类中。班级名称或 枚举名称隐藏在对象、函数或 枚举器名称可见。这个过程称为名称 隐藏。

    在成员函数定义中,本地名称的声明隐藏 同名的类成员的声明。这 派生类中成员的声明隐藏了 同名基类的成员。

    您也可以查看iso cpp标准:
    6.3.10 Name hiding[basic.scope.hiding]http://eel.is/c++draft/basic.scope.hiding

    【讨论】:

    • 感谢您的有用回答!。我不得不说,本质问题仍然存在。如上所述,您说关注点“struct hack”也称为“类型/非类型隐藏”。那么“struck hack”和“type/non-type”有什么相似之处呢?
    • 我认为我们遇到了语义问题。 c++ 中的 struct hack 在这里意味着与 C99 中的 struct hack 完全不同的概念,它应该被称为灵活数组(参见open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf)。另请注意,C++ 没有灵活的数组成员。我真的认为您可以建议网站 cpprefrence 删除“struct hack”部分。此外,在 iso cpp 标准中从未提及 struct hack 作为 c++ 功能(请参阅open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf)。我已经编辑了引用这篇论文的答案。
    • 范围和命名空间与问题的主题无关。类型/非类型隐藏指的是这个序列:struct vector {}; int vector = 42; 其中两个定义在同一范围内
    猜你喜欢
    • 2020-05-15
    • 2020-11-21
    • 2016-10-06
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多