Нет, это называется перегрузкой, и это не функция C. Для этого лучше всего создать отдельные функции.
Вы можете сделать это со всеми видами волшебства C (вы можете сделать все с достаточным количеством волшебства C), но результирующий код может быть настолько безобразным, что его невозможно будет поддерживать: -)
Например, в C11 введен общий выбор с первичным выражением _Generic
, и это позволяет вызывать различные функции в зависимости от типа входного аргумента. На самом деле он делает немного больше, но это тот аспект, который вас интересует, исходя из вашего вопроса.
Например, допустим, вы определяете две функции следующим образом:
int diffi (int a, int b) { return a - b; }
double diffd (double a, double b) { return a - b; }
Обычно вам приходится решать, что вызывать, основываясь на типах ввода. Функция общего выбора C11 позволяет вам сделать это:
#define diff(a,b) \
_Generic((a), \
double: diffd, \
int: diffi, \
default: diffX \
)(a,b)
И что это делает, в основном, при поиске макроса diff(x,y)
в исходном коде:
- определить тип выражения
(a)
, не вычисляя его;
- внедрить в исходный поток токен, соответствующий этому типу (или по умолчанию, если совпадение не найдено);
- вставьте в исходный поток текст
(a,b)
в конце.
Итак, если ваш исходный файл содержит строки:
x = diff (1, 2);
y = diff (1.0, 2);
это будет переведено на:
x = diffi (1 , 2);
y = diffd (1.0, 2);
давая вам вашу эффективную перегрузку.
Теперь это относительно простой случай, поскольку он опирается только на первый тип аргумента — вы увидите там дыру, если попытаетесь сделать:
z = diff (1, 2.0);
в том, что тип аргумента first — int
, поэтому вы получите:
z = diffi (1, 2.0);
что не будет тем, что вы на самом деле хотите сделать. Вот тут-то и возникают сложности, поскольку вам нужно охватить четыре возможности: {int/int, int/double, double/int, double/double}
и становится более сложной в зависимости от количества аргументов и возможных типов для каждого аргумента.
Однако этот полный ваш случай можно сделать с разумным использованием значений по умолчанию и вложенных общих выборов, например:
#define diff(a,b) \
_Generic((a), \
double: diffd, \
default: _Generic((b), \
double: diffd, \
default: diffi \
) \
)(a,b)
и это можно прочитать как:
- если тип
a
равен double
, используйте diffd
;
- в противном случае, если тип
b
равен double
, используйте diffd
;
- в противном случае используйте
diffi
.
- не забудьте также ввести аргументы.
Следующая полная программа (скомпилированная с помощью clang 3.0
) показывает эту функцию в действии:
#include <stdio.h>
int diffi (int a, int b) {
printf ("diffi %d %d", a, b);
return a - b;
}
double diffd (double a, double b) {
printf ("diffd %f %f", a, b);
return a - b;
}
#define diff(a,b) \
_Generic((a), \
double: diffd, \
default: _Generic((b), \
double: diffd, \
default: diffi \
) \
)(a,b)
int main (void) {
int i; double d;
i = diff (1 , 2 ); printf (" --> %d\n", i);
d = diff (1.0, 2 ); printf (" --> %f\n", d);
d = diff (1 , 2.0); printf (" --> %f\n", d);
d = diff (1.0, 2.0); printf (" --> %f\n", d);
return 0;
}
Вывод этой программы:
diffi 1 2 --> -1
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000
показывая, что для четырех возможностей вызывается правильная функция.
И на самом деле, как указывает rici в комментарии, вы можете полагаться на правила продвижения C, где добавление double
и int
(в любом порядке) дают вам double
, а добавление двух переменных int
дает вам int
:
#define diff(a,b) _Generic((a+b), double:diffd, default:diffi)(a,b)
person
paxdiablo
schedule
21.10.2014