2015年11月22日 星期日

C 多型

剛剛在翻 tgmath.hsource code 的時候發現,在 llvm 的實作裡有一個 attribute "__overloadable__"(ref: http://clang.llvm.org/doxygen/tgmath_8h_source.html)

tgmath.hC99 標準標頭之一,主要目的是讓我們在呼叫 math.h 裡的函式的時候不需要一直去注意呼叫的函式型態

__overloadable__ 的用法就是放在 functiondefinition 旁邊,像這樣,可以達成真正的多型:

__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 自己的 extensiongcc 並沒有提供這個功能 (所以趕快換來 clang 的行列吧) 所以在使用上必須小心

不過竟然只是 clangextension,真的是沒有過癮到......
(ref: https://ohse.de/uwe/articles/gcc-attributes.htmlhttp://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

沒有留言:

張貼留言