簡體   English   中英

使用預處理器對C / C ++進行元編程

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM