在C中使用模板function的最短例子?

我如何处理函数echo_tpl ,它可以采用intstring类型的1个参数,并将其打印出来?

C没有模板。 我认为你能做的最好的事情就是使用一个联合或让函数有不同的名字。 后一种具有不同名称的方法是准标准方法(例如fabs fabsf fabsl ,也是OpenGL 大量使用的 ,它也解释了C不能重载function的事实)

 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(); } 

或者你可以采用联合方式,它将使函数名相等,而是用meta信息炸毁参数类型。

 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" }); } 

如果你想将值存储在某处然后执行print函数而不关心传递给它的值类型,那么union方式特别适合。 在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没有类型通用输出函数。 当然,如果您使用此function,您的代码将变得不可移植。

将模板转换为C的传统方法是使用预处理器。 我会做这样的事情:

 // this creates each template "instance" #define ECHO_TPL_IMPLEMENT(t) void echo_tpl_##t(t param){\ /* this is where you write your function that uses param */ \ } // this calls the specific template instance #define ECHO_TPL(t, val) echo_tpl_##t(val) // as i wrote it, the function only accepts a 1 word parameter type // so for simplicity, i'm defining char* to be string typedef char *string; // i implement the function for the types int and string ECHO_TPL_IMPLEMENT(int) // creates echo_tpl_int ECHO_TPL_IMPLEMENT(string) // creates echo_tpl_string main() { // then i just call them and let the preprocessor handle it ECHO_TPL(string, "meep"); // will call echo_tpl_string ECHO_TPL(int, 10); // will call echo_tpl_int } 

这就是原始C ++编译器处理模板的方式,只有它们(并且至今仍然如此)更复杂的类型修改规则,其中我假设类型是1个单词,如果它们不是,则必须键入它们。

编辑 :请注意,我将该函数留空。 这确实是你在C中编写“模板化函数”的方法,但是我不能像你要求的那样编写参数,因为C没有一个与类型无关的文件编写api。 printfwrite需要有关实际类型的信息(通过%d%s以及分别写入的字节长度),我们没有。

另请注意,这也适用于C ++。 您不能使用C api从模板写入文件,您只能使用cout (或者使用boost格式或类似的东西)。 你必须考虑你想用实际的function做什么。

最近,但值得补充的是,从C11标准开始,C现在通过使用_Generic表达式对重载提供了一些非常有限的支持,这些表达式在编译时根据输入的类型选择正确的结果表达式。 什么都不像模板,但他们可以像这样回答这个老问题:

 #define echo_tpl(X) _Generic((X), int: echo_tpl_i, \ char *: echo_tpl_s)(X) void echo_tpl_s(char const *string) { /* ... */ } void echo_tpl_i(int number) { /* ... */ } int main(void) { echo_tpl("Hello world"); echo_tpl(42); } 

您仍然必须像在C99中那样使用单独的名称来定义函数实现,但是您可以使用C ++ – ish名称定义一个宏,该名称在每个使用点插入_Generic表达式,以便为该调用选择正确的版本网站,没有让function用户考虑参数类型。

它似乎需要永远完全采用C标准,我不知道哪个编译器实现了这个function,但如果有更多的人出去使用它,它会越来越普遍!

 template  void echo_tpl(const T& t) { std::cout << t; } 

编辑:我没有发现c标签。 以上答案仅适用于C ++。