阅读更多GCC的源代码,semantics.c:
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;
}
}
此代码表示在以下情况下将类型标记为透明:
- 它是一个结构体,而不是一个模板;
- 它在命名空间级别,命名空间是
std::decimal。
- 它被命名为
decimal32、decimal64或decimal128。
在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 在 cmets 中所建议的那样不符合 GCC?我不知道......你应该能够用你想要的任何两种不同类型编写重载函数。但是OTOH,不使用一些编译器扩展是不可能得到Decimal32类型的,所以这种类型的含义是实现定义的......