什么是“types透明类”?

使用gcc来编译一个包含对十进制数据types支持的程序,我最近遇到了下面的错误:

error: type transparent class 'std::decimal::decimal32' has base classes

快速浏览一下GCC的源代码树,发现这个错误信息在gcc/cp/class.c

什么是“透明类”? 为什么这样的class级有“基础class”是错误的?

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

这个代码意味着一个types被标记为透明的,如果:

  • 这是一个结构,但不是一个模板;
  • 它在命名空间级别,该命名空间是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)); 

评论在这里是关键。 我认为这意味着透明types被replace为其第一个成员可以使用的任何位置。 例如,在我的include/decimal ,类std::decimal::decimal32有一个std::decimal::decimal32types的__decfloat32 (来自之前的typedef float __decfloat32 __attribute__((mode(SD))); ),所以任何需要__decfloat32可以采取一个std::decimal::decimal32 ,反之亦然。 即使是function装饰也是一样的。 这个想法很可能使这个ABI类与C类兼容_Decimal32_Decimal64_Decimal128

现在,你怎么得到一个基类与class decimal32类? 我唯一的猜测是,你是包括不兼容的(也许更老的)头文件,具有完全不同的实现。

UPDATE

经过一番调查,看起来我对ABI和function装修的猜测是对的。 以下代码:

 #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的一致? 我不知道…你应该能够用任何你想要的两种不同的types来编写重载函数。 但是OTOH,如果不使用一些编译器扩展,就不可能得到Decimal32types,所以这种types的含义是实现定义的。

正如我的一个评论中提到的, types透明的类是一些基本types的包装类,比如整型等。

它们被称为透明的,因为它们使用了运算符重载 ,这使得它们的行为就像它们所包装的基本types一样。

IE,要在一个类中透明地包装一个int ,你需要重载=运算符, ++运算符等。

显然, GNU的libstdc ++对某些types使用了这样的类。 不知道为什么…

关于基类问题 ,虽然我不是100%确定的,但这是一个猜测。

在处理C ++中的inheritance时,通常需要声明方法来解决上传问题。

将方法声明为虚拟将告诉编译器为这些方法创build一个虚拟表 ,以便在运行时查看它们。
这当然会增加类的实例大小

对于一个types透明的类,这是不可接受的,因为编译器不能将这样一个类的实例放在一个寄存器中 (即当传递参数等)时, 不像包装types ,所以类不再透明了。

编辑

我不知道如何在GCC中声明这样一个透明类。 我能想到的最接近的就是透明的工会

http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

就像是:

 class IntWrapper { int _x; /* Constructor, operator overloads... */ }; typedef union { int integerValue; IntWrapper integerWrapper; } IntUnion __attribute__( ( __transparent_union__ ) ); 

我的GCC版本似乎不支持它,但根据文档(请参阅上面的链接),这将允许intIntWrapper透明地使用相同的调用约定作为int传递给函数。