剛剛在翻 tgmath.h 的 source code 的時候發現,在 llvm 的實作裡有一個 attribute "__overloadable__"(ref: http://clang.llvm.org/doxygen/tgmath_8h_source.html)
tgmath.h 是 C99 標準標頭之一,主要目的是讓我們在呼叫 math.h 裡的函式的時候不需要一直去注意呼叫的函式型態
__overloadable__ 的用法就是放在 function 的 definition 旁邊,像這樣,可以達成真正的多型:
__attribute__((__overloadable__)) int print(char c) { return printf("%c\n", c); }
__attribute__((__overloadable__)) int print(int i) { return printf("%d\n", i); }
__attribute__((__overloadable__)) int print(float f) { return printf("%f\n", f); }
而且不只是 parameter list 可以 overload,連 return type 都可以!可惜的是這只是 clang 自己的 extension,gcc 並沒有提供這個功能 (所以趕快換來 clang 的行列吧) 所以在使用上必須小心
不過竟然只是 clang 的 extension,真的是沒有過癮到......
(ref: https://ohse.de/uwe/articles/gcc-attributes.html, http://clang.llvm.org/docs/AttributeReference.html#overloadable)
那麼再來介紹一個和多型有關的東西好了
C11 引進了一個新的 keyword "_Generic",用它可以做到一點點小多型(ref: https://en.wikipedia.org/wiki/C11_(C_standard_revision))
可以寫一個 macro 來幫忙
#define print(x) _Generic((x), char: print_c, int: print_i, float: print_f)((x))
接著各函式的實作
int print_c(char c) { return printf("%c\n", c); }
int print_i(int i) { return printf("%d\n", i); }
int print_f(float f) { return printf("%f\n", f); }
然後就可以呼叫了
int main(void)
{
char c = 'x';
print(c);
return 0;
}
在編譯的時候要記得給編譯器 -std=c11 的參數,開啟 c11 的支援喔~
root@localhost:~# clang -std=c11 -o generic generic.c
root@localhost:~# ./generic
x
root@localhost:~#
以上都是 compile-time type determination,純 C 目前好像還無法 runtime type determine,想要這些進階功能,還是乖乖用 C++ 吧 XD