Что __tg_promote делает в tgmath.h

Я смотрю на tgmath.h и пытается понять, как именно он выбирает правильную функцию на основе размера входного значения.

Специальный соус, кажется, это __tg_promote макрос, но чем глубже я копаю, тем глубже эта загадка. У кого-нибудь есть короткий ответ на что __tg_promote на самом деле

1

Решение

В реализации Clang tgmath.h похоже, что __tg_promote на самом деле функция, а не макрос. Определение можно найти Вот.

typedef void _Argument_type_is_not_arithmetic;
static _Argument_type_is_not_arithmetic __tg_promote(...)
__attribute__((__unavailable__,__overloadable__));
static double               _TG_ATTRSp __tg_promote(int);
static double               _TG_ATTRSp __tg_promote(unsigned int);
static double               _TG_ATTRSp __tg_promote(long);
static double               _TG_ATTRSp __tg_promote(unsigned long);
static double               _TG_ATTRSp __tg_promote(long long);
static double               _TG_ATTRSp __tg_promote(unsigned long long);
static float                _TG_ATTRSp __tg_promote(float);
static double               _TG_ATTRSp __tg_promote(double);
static long double          _TG_ATTRSp __tg_promote(long double);
static float _Complex       _TG_ATTRSp __tg_promote(float _Complex);
static double _Complex      _TG_ATTRSp __tg_promote(double _Complex);
static long double _Complex _TG_ATTRSp __tg_promote(long double _Complex);

Это функция с множественными перегрузками (не разрешена в C вообще) и без определения, что хорошо, потому что она никогда не вызывается! __tg_promote используется только для определения типа, которому должен быть присвоен числовой тип. (Интегральные типы для double; Типы с плавающей точкой для себя.) Это ясно, когда вы смотрите на следующие несколько макросов:

#define __tg_promote1(__x)           (__typeof__(__tg_promote(__x)))
#define __tg_promote2(__x, __y)      (__typeof__(__tg_promote(__x) + \
__tg_promote(__y)))
#define __tg_promote3(__x, __y, __z) (__typeof__(__tg_promote(__x) + \
__tg_promote(__y) + \
__tg_promote(__z)))

__tg_promote функция не вызывается, потому что это происходит внутри конкретного компилятора __typeof__ макро. __tg_promote1 макрос просто расширяется до повышенный тип его аргумент, в скобках. __tg_promote2 расширяется до типа (снова заключенного в скобки), который получился бы, если бы были добавлены два значения повышенных типов его аргументов. Так, например, __tg_promote2(0.0f, 0) было бы (double), так как добавление float и double (результат продвижения int) дает double, __tg_promote3 похож.

Остальная часть заголовка состоит из перегруженных определений функций, которые делегируются соответствующим обычным функциям C:

// atan2

static float
_TG_ATTRS
__tg_atan2(float __x, float __y) {return atan2f(__x, __y);}

static double
_TG_ATTRS
__tg_atan2(double __x, double __y) {return atan2(__x, __y);}

static long double
_TG_ATTRS
__tg_atan2(long double __x, long double __y) {return atan2l(__x, __y);}

Для того, чтобы иметь возможность позвонить, скажем, atan2(1.0f, 1) мы должны быть в состоянии делегировать __tg_atan2(double, double), Это где __tg_promote2 приходит, чтобы определить, что, когда у нас есть один float аргумент и один int аргумент, оба должны быть преобразованы в double:

#define atan2(__x, __y) __tg_atan2(__tg_promote2((__x), (__y))(__x), \
__tg_promote2((__x), (__y))(__y))

Так что в этом случае __tg_promote2((__x), (__y)) расширяется до (double) и мы получаем __tg_atan2((double)(__x), (double)(__y))что именно то, что мы хотим.

2

Другие решения


По вопросам рекламы [email protected]