最近因為需要在程式中埋下紀錄使用者過程中用到了那些 function,這樣方便日後追蹤重現結果。當然最簡單的方法是在每個 function 內都明確地用 logger 之類的寫進 log 裡,不過 python 有更簡單更不容易出錯的方式可以達到效果,因為用 logger 很容易在未來程式改版時有所疏漏。
方法基本上有三種:proxy, build-in __getattribute__(), decorator
最近因為需要在程式中埋下紀錄使用者過程中用到了那些 function,這樣方便日後追蹤重現結果。當然最簡單的方法是在每個 function 內都明確地用 logger 之類的寫進 log 裡,不過 python 有更簡單更不容易出錯的方式可以達到效果,因為用 logger 很容易在未來程式改版時有所疏漏。
方法基本上有三種:proxy, build-in __getattribute__(), decorator
大家有沒有遇過這種狀況呢? 一些資料結構 (ex: heap, binary tree) 的節點數量往往是 2 的冪次方 - 1;或者是為了程式效率,把陣列或是 struct 的大小設定成 2 的冪次方。以往在寫這類數值時通常會利用 #define 或者是 constexpr 等等之類的方法把這種數值變成某個有意義的變數,像是這樣:
constexpr int BITSIZE = 10;
constexpr int BUFSIZE = 1024;
但這種時候會遇到一個小麻煩:開發過程中為了程式效率會常常調整這些數值,所以為了盡可能減少錯誤會有各種方式來做這些基礎設定。比方說 BUFSIZE 就可以改成 (1 << BITSIZE) 來避免改了 BITSIZE 忘記改掉 BUFSIZE。
當然,現在 compiler 已經很厲害了,如果某些基礎設定值在編譯期 (compile-time) 就是常數,現在也有不少方法可以讓後續的衍伸運算也都變成編譯期的常數,從而減少執行期的時間。這篇文章要做的主要是介紹用 metaprogramming 把這些運算通通轉成編譯期的常數。
事情是這樣的,有人問我他想做到這件事:
enum class Enum {A, B, C ... };
template <Enum E, int N>
struct MyStruct {
void func();
};
template <int N>
void MyStruct<Enum::A, N>::func() {...}
看完後我就說了,你想做的事 function 的偏特化,這在 C++ 是不被允許的,所以當然會編譯失敗囉
當然,下一個問題就是:那要怎麼做?
以下提供幾個方法 (先不考慮整個 class 重構把 template argument 拆掉)
最近做的東西有個需求有點特別,在程式跑的過程中會在某一步讓使用者可以看看目前有哪些變數他可以用,然後讓他選擇要抓哪個變數出來做後續處理,概念上有點像是 gdb 的 info variables。
然而這就表示我們程式中會需要接受一個使用者輸入的字串當作 key 去存取變數,所幸程式是用 python 寫的,所以類似的方法不難做。