C не имеет шаблонов.Я думаю, что лучшее, что вы могли бы сделать, это использовать объединение или иметь имена функций с разными именами.Последний способ иметь разные имена - это квази-стандартный метод (например, fabs
fabsf
fabsl
, также интенсивно используемый OpenGL, который также объясняет тот факт, что C не можетфункции перегрузки)
void echo_tpl_s(char const *string) { /* ... */ }
void echo_tpl_i(int number) { /* ... */ }
int main(void) {
echo_tpl_s("Hello world");
echo_tpl_i(42);
}
Если общего кода много, вы можете решить выделить его в отдельные функции
void echo_tpl_s(char const *string) {
prepare_output_device();
printf("%s", string);
unprepare_output_device();
}
void echo_tpl_i(int number) {
prepare_output_device();
printf("%d", number);
unprepare_output_device();
}
Или вы можете взять union путь, который будет иметь имена функций равными, но вместо этого взорвать тип параметра с метаинформацией.
enum Type {
Number,
String
};
struct Value {
enum Type type;
union {
int number;
char const *string;
} u;
};
void echo_tpl(struct Value value) {
switch(value.type) {
case Number: printf("%d", value.u.number); break;
case String: printf("%s", value.u.string); break;
}
}
int main(void) {
echo_tpl((struct Value) {
.type = String,
.u.string = "Hello world"
});
}
Способ объединения особенно хорошо подходит, если вы хотите где-то сохранить значение, а затем выполнить функцию печати, не заботясь о том, какой тип значения вы передаете ему.В C89 вам нужно было бы создать значение отдельно, так как оно не имеет составных литералов
int main(void) {
struct Value value;
value.type = String;
value.u.string = "Hello world";
echo_tpl(value);
}
Это хорошая идея для создания функций, хотя
struct Value stringval(char const *string) {
struct Value value;
value.type = String;
value.u.string = string;
return value;
}
struct Value numberval(int number) {
struct Value value;
value.type = Number;
value.u.number = number;
return value;
}
int main(void) {
echo_tpl(stringval("Hello world!"));
}
Некоторые компиляторы могут предоставлять расширения для написания таких вещей.Например, Clang обеспечивает перегрузку функции в C.
void echo_tpl(int value) __attribute__((overloadable)) {
printf("%d", value);
}
void echo_tpl(char const *value) __attribute__((overloadable)) {
printf("%s", value);
}
Это решает сторону вызова функции не зависеть от типа.Что касается определения, вам все равно придется писать код дважды.Это главным образом потому, что (как объясняет другой ответ) C не имеет типовых функций вывода.Конечно, если вы используете эту функцию, ваш код становится непереносимым.