Ссылка, которую вы нашли, верна: C не поддерживает перегрузку, как таковую.
Что она имеет (если мы говорим о реальных C, а не исторических c версиях ) является универсальным селектором c, который позволяет вам написать собственный макрос, который выполняет динамическую c диспетчеризацию.
C99 представил заголовок tgmath.h
, который допускает определенные математические функции быть перегруженным для использования с аргументами с плавающей запятой различной ширины, а в некоторых случаях со сложными аргументами. Однако в C99 не было введено ни одного средства, позволяющего обобщить эту функцию для других функций. Селектор generi c, представленный в C11, является этим средством.
Селектор имеет форму _Generic(select-expression, type-associations)
, где type-associations
состоит из разделенного запятыми списка пар вида type : expression
. Селектор будет заменен выражением, соответствующим типу select-expression
. Одним из type
s может быть ключевое слово default
; остальные должны быть уникальными полными типами (т. е. никакие два типа в списке не могут быть совместимы) [Примечание 1]. Важно отметить, что все выражений в списке ассоциаций должны компилироваться без ошибок, а не только выбранное. Обычно выражения будут указателями на функции, а не на вызовы функций.
Пример может прояснить это. Предположим, у нас есть две функции (которые имеют разные имена, поэтому это не перегрузка имен):
int max_int(int a, int b) { return a > b ? a : b; }
double max_dbl(double a, double b) { return a > b ? a : b; }
Теперь мы можем определить макрос MAX:
#define MAX(a, b) _Generic((a)+(b), \
int : max_int, \
double : max_dbl)(a, b)
Здесь я используйте a+b
в качестве выражения селектора, а не a
, потому что тип a+b
- это тип, который получается в результате обычных арифметических c преобразований. Если бы я просто использовал a
, то MAX(3, 5.7)
дал бы неожиданный результат, потому что селектор generi c выбрал бы max_int
, а 5.7
был бы тихо обрезан до 5. С a+b
, тип селектора будет double
, что приведет к вызову max_dbl
, для которого оба значения будут преобразованы в удвоение.
Я могу избежать использования (a)+(b)
в макросе, потому что _Generic
не оценивает выражение селектора (например, sizeof
). Таким образом, нет опасности двойной оценки аргументов с побочными эффектами.
Примечания:
- Тип обобщенной c ассоциации не может быть VLA (массив переменной длины), даже если компилятор их реализует. Но с любым другим полным типом все в порядке, даже указатель на неполный тип.