[英]Metaprogramming C/C++ using the preprocessor
所以我有這個巨大的樹,基本上是一個大的開關/案例,帶有字符串鍵和一個公共對象上的不同函數調用,具體取決於鍵和一個元數據。
每個條目基本上都是這樣的
} else if ( strcmp(key, "key_string") == 0) {
((class_name*)object)->do_something();
} else if ( ...
do_something
可以有不同的調用,所以我不能只使用函數指針。 此外,某些鍵需要將對象強制轉換為子類。
現在,如果我用更高級別的語言編寫代碼,我會使用lambdas字典來簡化這一過程。
在我看來,我可以使用宏來簡化這類
case_call("key_string", class_name, do_something());
case_call( /* ... */ )
其中case_call
是一個宏,可以將此代碼擴展到第一個代碼片段。
然而,我非常關注這是否會被視為好風格。 我的意思是,它會減少打字工作並改善代碼的干燥度,但它確實似乎在某種程度上濫用了宏系統。
你會走那條路,還是整理出整條路? 你這樣做的原因是什么?
編輯
一些澄清:
此代碼用作簡化腳本API之間的粘合層,該API作為簡單的鍵值屬性訪問C ++ API的幾個不同方面。 這些屬性在C ++中以不同的方式實現:有些具有getter / setter方法,有些是在特殊結構中設置的。 腳本操作引用C ++對象轉換為公共基類。 但是,某些操作僅適用於某些子類,必須進行轉換。
接下來,我可能會更改實際的C ++ API,但目前,它必須被視為不可更改。 此外,這必須在嵌入式編譯器上工作,因此(遺憾的是)boost或C ++ 11不可用。
在我看來,適當使用宏。 畢竟,它們是為了避免語法重復而制作的。 然而,當你有語法重復時,它並不總是語言的錯誤 - 可能有更好的設計選擇可以讓你完全避免這個決定。
一般的智慧是使用表映射鍵來執行操作:
std::map<std::string, void(Class::*)()> table;
然后查找並一次調用該操作:
object->*table[key]();
或使用find
檢查失敗:
const auto i = table.find(key);
if (i != table.end())
object->*(i->second)();
else
throw std::runtime_error(...);
但是如果你說沒有函數的共同簽名(即你不能使用成員函數指針)那么你實際上應該做什么取決於你不知道的項目細節。 可能是一個宏是唯一能夠忽視你所看到的重復的方法,或者可能是一種更好的方式來實現它。
問問自己: 為什么我的函數采用不同的論點? 我為什么要使用演員表? 如果您要調度對象的類型,則可能需要引入通用接口。
我建議你稍微改變角色。 你說這個對象已經是一個知道如何處理某種情況的類了,所以在你的基類中添加一個virtual void handle(const char * key)
,讓對象檢查實現是否適用於它並做什么是必要的。
這不僅可以消除長if-else-if鏈,而且還可以更安全,並且可以更靈活地處理這些事件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.