En lisant un peu plus le code source de GCC, en 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;
}
}
Ce code signifie qu'un type est marqué transparent si :
- Il s'agit d'une structure, mais pas d'un modèle ;
- Et c'est au niveau de l'espace de nom, et cet espace de nom est
std::decimal
.
- Et il s'appelle
decimal32
, decimal64
o decimal128
.
Sur class.c
il y a le contrôle d'erreur que vous avez rencontré, et quelques autres.
Et dans 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));
Le commentaire est la clé ici. Je pense que cela signifie qu'un type transparent est remplacé par le type de son premier (et seul) membre, et qu'il peut donc être utilisé partout où son premier membre le peut. Par exemple, dans mon include/decimal
la classe std::decimal::decimal32
a un seul champ de type __decfloat32
(d'un précédent typedef float __decfloat32 __attribute__((mode(SD)));
), donc toute fonction qui prend un __decfloat32
peut prendre un std::decimal::decimal32
et vice-versa. Même la décoration des fonctions est faite de la même manière. L'idée est probablement de rendre l'ABI de ces classes compatible avec les types C. _Decimal32
, _Decimal64
y _Decimal128
.
Maintenant, comment obtenez-vous un class decimal32
avec les classes de base ? Ma seule hypothèse est que vous incluez des fichiers d'en-tête incompatibles (peut-être plus anciens), avec une implémentation totalement différente.
UPDATE
Après quelques recherches, il semble que ma supposition sur l'ABI et la décoration des fonctions soit juste. Le code suivant :
#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) {}
donne la curieuse erreur :
/tmp/ccr61gna.s: Assembler messages:
/tmp/ccr61gna.s:1291: Error: symbol `_Z3fooDf' is already defined
C'est-à-dire que le compilateur frontal ne voit aucun problème dans la surcharge et émet le code asm, mais comme les deux fonctions sont décorées de la même façon, l'assembleur échoue.
Maintenant, est-ce une non-conformité de GCC, comme le suggère Ben Voigt dans les commentaires ? Je ne sais pas... vous devriez être capable d'écrire des fonctions surchargées avec les deux types différents que vous voulez. Mais d'un autre côté, il est impossible de faire en sorte que la fonction Decimal32
sans utiliser une extension du compilateur, donc la signification de ce type est définie par l'implémentation...