使用gcc编译包含对十进制数据类型的支持的程序,我最近遇到以下错误:
error: type transparent class 'std::decimal::decimal32' has base classes
快速浏览GCC的源代码树显示此错误消息在gcc/cp/class.c中找到。

什么是“类型透明类”?为什么这样的类具有“基类”是错误的?

最佳答案

semantics.c中阅读更多GCC的源代码:

  if (TREE_CODE (t) == RECORD_TYPE
      && !processing_template_decl)
    {
      tree ns = TYPE_CONTEXT (t);
      if (ns && TREE_CODE (ns) == NAMESPACE_DECL
          && DECL_CONTEXT (ns) == std_node
          && DECL_NAME (ns)
          && !strcmp (IDENTIFIER_POINTER (DECL_NAME (ns)), "decimal"))
        {
          const char *n = TYPE_NAME_STRING (t);
          if ((strcmp (n, "decimal32") == 0)
              || (strcmp (n, "decimal64") == 0)
              || (strcmp (n, "decimal128") == 0))
            TYPE_TRANSPARENT_AGGR (t) = 1;
        }
    }

此代码表示在以下情况下将类型标记为透明:
  • 这是一个结构,但不是模板;
  • 它在 namespace 级别,该 namespace 是std::decimal
  • 它被命名为decimal32decimal64decimal128

  • class.c中,您遇到了错误检查,还有更多错误检查。

    并在mangle.c中:
          /* According to the C++ ABI, some library classes are passed the
             same as the scalar type of their single member and use the same
             mangling.  */
          if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
            type = TREE_TYPE (first_field (type));
    

    评论在这里很关键。我认为这意味着将透明类型替换为其第一(也是唯一)成员的类型,因此可以在第一成员可以使用的任何位置使用它。例如,在我的include/decimal中,类std::decimal::decimal32具有一个__decfloat32类型的字段(来自先前的typedef float __decfloat32 __attribute__((mode(SD)));),因此,采用__decfloat32的任何函数都可以采用std::decimal::decimal32,反之亦然。甚至功能装饰也一样。想法可能是使此类ABI与C类型_Decimal32_Decimal64_Decimal128兼容。

    现在,如何获得带有基类的class decimal32?我唯一的猜测是,您将包含不兼容的(可能是较旧的)头文件,实现方式完全不同。

    更新

    经过一番调查,看来我对ABI和功能装饰的猜测是正确的。如下代码:
    #include <decimal/decimal>
    using namespace std::decimal;
    
     //This is a synonym of C99 _Decimal32, but that is not directly available in C++
    typedef float Decimal32 __attribute__((mode(SD)));
    
    void foo(decimal32 a) {}
    void foo(Decimal32 a) {}
    

    给出了奇怪的错误:
    /tmp/ccr61gna.s: Assembler messages:
    /tmp/ccr61gna.s:1291: Error: symbol `_Z3fooDf' is already defined
    

    也就是说,编译器前端看不到重载问题,并发出asm代码,但是由于两个函数的装饰方式相同,因此汇编器将失败。

    现在,这是否像Ben Voigt在评论中所建议的那样不符合GCC?我不知道...您应该能够使用任何两种不同的类型编写重载函数。但是OTOH,如果不使用某些编译器扩展就不可能获得Decimal32类型,因此这种类型的含义是实现定义的...

    关于c++ - C++-什么是 “type transparent class”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17709264/

    10-10 12:44