Ответ 1
Чтение исходного кода 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
с базовыми классами? Мое единственное предположение: вы включаете несовместимые (возможно, более старые) файлы заголовков с совершенно другой реализацией.
UPDATE
После некоторого расследования, похоже, что я догадываюсь о том, что 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, но поскольку обе функции декорированы одинаково, ассемблер терпит неудачу.
Теперь, является ли это несоответствием GCC, как предлагает Бен Фойгт в комментариях? Я не знаю... вы должны иметь возможность писать перегруженные функции с любыми двумя разными типами, которые вы хотите. Но OTOH невозможно получить тип decimal32
без использования некоторого расширения компилятора, поэтому значение этого типа определяется реализацией...