2016-09-21 15 views
1

考慮下面的代碼:C++函數switch語句或陣列抽象超過宏值

#define VAL_A 0 
#define VAL_B 1 
#define VAL_C 2 

void TestSwitch01(uint32 val) 
{ 
    printf("%u: ", op); 
    switch (val) 
    { 
    case VAL_A: printf("aaa\n"); break; 
    case VAL_B: printf("bbb\n"); break; 
    case VAL_C: printf("ccc\n"); break; 
    default: printf("ddd\n"); 
    } 
} 

#define VAL_A 10 
#define VAL_B 11 
#define VAL_C 12 

void TestSwitch02(uint32 op) 
{ 
    printf("%u: ", op); 
    switch (val) 
    { 
    case VAL_A: printf("aaa\n"); break; 
    case VAL_B: printf("bbb\n"); break; 
    case VAL_C: printf("ccc\n"); break; 
    default: printf("ddd\n"); 
    } 
} 

在本例中,我有三個VAL_*宏和兩個TestSwitch*()功能。但是,假設我有這種模式,但是具有5000個宏和20個TestSwitch*()函數(換句話說--202個不同版本的VAL_A-0,10等)。此外,我有#define在單獨的文件中......因此foo001.h具有(0 1 2)VALfoo002.h具有(10 11 12)VAL的s。

我不想複製粘貼20個版本的函數,因爲它是相同的函數。所以我真的想編寫一個抽象宏的函數。

很明顯,我可以使用變量,但我不想這樣做,因爲變量將在運行時設置,這將是緩慢的。我希望編寫C++代碼,使編譯器生成20個版本的TestSwitch*(),每個版本對應於20個不同的5000個宏的其中一個。

我想避免寫一個宏的僞函數,因爲你不能進入,加上它很難閱讀(也語法突出顯示和智能感知不起作用)。

我考慮過使用模板函數,但使用5000個宏VAL_*,它會非常瘋狂...... template void <uint32 VAL_A, uint32 VAL_B ... VAL_4999> TestSwitch(...)

我也嘗試着用函數指針數組替換switch()語句來實現它(但是,在填充數組時,我仍然遇到了複製粘貼代碼問題。

我覺得C++有工具來做我想做的事,但我不知道如何......任何想法?

基本上我想要生成20個函數TestSwitchXX()的副本 - 每個5000 VAL_*的一套。

也許有一些技巧使用多個文件和#include的和#if的?

+3

C++不是瑞士軍刀。它不能做任何事情。如果這真的是你想要的(並且我明白爲什麼你會想要它),並且switch語句的所有值都有一些邏輯模式,那麼使用正確的工具來完成正確的工作:編寫一個簡單的Perl腳本,或者使用您選擇的腳本語言來機器生成所有意大利麪代碼,並將其集成到您的構建系統中。如果這對'lex/flex'和'yacc/bison'來說足夠好,這裏就夠了。 –

+0

使用連接運算符 – Raindrop7

+1

查找表。設計一個包含密鑰和指向處理密鑰的函數的指針的結構。放置到地圖或矢量。搜索密鑰,然後如果找到密鑰,則通過取消引用函數指針來執行* associated *函數。 –

回答

2

一個正確的C++該解決方案將與#define s到做掉,並使用結構中枚舉:

struct Foo { 
    enum { VAL_A = 0, VAL_B = 1, VAL_C = 2 }; 
}; 

struct Bar { 
    enum { VAL_A = 10, VAL_B = 11, VAL_C = 12 }; 
}; 

template<typename T> 
void TestSwitch(int op) 
{ 
    std::cout << op << ": "; 
    switch (op) { 
     case T::VAL_A: std::cout << "aaa\n"; break; 
     case T::VAL_B: std::cout << "bbb\n"; break; 
     case T::VAL_C: std::cout << "ccc\n"; break; 
     default: break; 
    } 
} 

演示:http://ideone.com/u3kTtF

你可以同時更換struct只有一個enum class但你只能有值,結構選項給你的機會,包括其他值,描述的事情有關T可能以後是你seful。

枚舉類演示:http://ideone.com/DBZuyn

+0

這是我迄今爲止最喜歡的答案。我可能會編寫一個python腳本來將我的#define頭文件轉換爲枚舉的 – pemcode

0

XMacros - 他們走向......讓我看看......葉氏,2001年

上線:

「generate_testswitch.h」

#define IMPLEMENT_TEST_SWITCH(N) void TestSwitch#N(uint32 val) \ 
{ \ 
    printf("%u: ", op); \ 
    switch (val) \ 
    { \ 
    case VAL_A: printf("aaa\n"); break; \ 
    case VAL_B: printf("bbb\n"); break; \ 
    case VAL_C: printf("ccc\n"); break; \ 
    default: printf("ddd\n"); \ 
    } \ 
} 

「testswitch1。C」

// you may isolate these in yet another header 
#define VAL_A 0 
#define VAL_B 1 
#define VAL_C 2 

#include "generate_testswitch.h" 

IMPLEMENT_TEST_SWITCH(01) 
+0

這正是我的OP所說的「宏僞函數」所表達的意思......我想避免編寫一個宏僞函數,因爲你無法進入(使用調試器),加上它很難閱讀(還有語法高亮和智能感知不起作用)。每行結尾都是奇怪的語法,但更重要的是Visual Studio(和我認爲gdb)不支持調試這些或做適當的智能感知和語法高亮我猜,因爲宏是預處理器字符串替換而不是「真正的」 C++代碼。 – pemcode

+0

@pemcode「更重要的是Visual Studio(和我認爲gdb)不支持調試這些」。你知道,產生編譯未來戰爭代碼的工具並不是一個奇特的想法。所以,我想你可以編寫一個C++實用程序來讀取這些「#define VAL_A」頭文件,然後將它們作爲函數定義打包到名爲「my_func_X.cpp」的文件中。 –

0

我認爲使用模板的功能,但與5000個VAL_*宏,這將是非常瘋狂...... template void <uint32 VAL_A, uint32 VAL_B ... VAL_4999> TestSwitch(...)

爲了您將問題標記爲c++,我假定可以使用該標準的最新版本(或至少C++ 11)。
因此,不,使用模板不會很瘋狂。
你可以做這樣的事情與可變參數模板:

template<typename T, T... V> 
void TestSwitch(uint32_t val) { 
    // ... 
} 

因此,你可以調用它爲:

TestSwitch<int, 10, 11, 12>(42); 

我不知道你要使用這些值做什麼,所以很難說明函數的主體是如何寫入的。
作爲一個玩具例子,它遵循如果val包含在V...,檢查的實現:

template<typename T, T... V> 
void TestSwitch(uint32_t val) { 
    bool found = false; 
    int arr[] = { 0, (found = found || (val == V), 0)... }; 
    (void)arr; 
    std::cout << "found: " << found << std::endl; 
} 

其他問題,可能需要一個空的情況下,等一個遞歸。


只要你處理的範圍,你也可以做這樣的事情:

#include <cstddef> 
#include <functional> 
#include <iostream> 

template<std::size_t B, std::size_t... I> 
void TestSwitch(uint32_t val, std::index_sequence<I...>) { 
    bool found = false; 
    int arr[] = { 0, (found = found || (val == (B+I)), 0)... }; 
    (void)arr; 
    std::cout << "found: " << found << std::endl; 
} 

template<std::size_t B, std::size_t N> 
void TestSwitch(uint32_t val) { 
    TestSwitch<B>(val, std::make_index_sequence<N>{}); 
} 

int main() { 
    TestSwitch<40, 3>(42); 
    TestSwitch<40, 3>(0); 
} 

在這種情況下,我們使用基地調用TestSwitch(即起始值)以及範圍的長度,那麼我們依靠std::make_index_sequence和另外一個函數來自己生成範圍並完成工作。

+0

,其中有5000個值,所以即使使用可變參數模板,也會非常瘋狂地調用 TestSwitch (42)其中...(5000-3 = 4997)整數輸出 - 它非常漫長和繁瑣。在我的真實例子中有20x20 = 400版本的TestSwitch(),所以我會有400個這樣的模板調用,每個模板調用5000個模板參數。在那一點上,我可能只是做我希望避免的複製粘貼方法。 – pemcode

+0

我希望有一種方法可以#include我的兩個定義5000 #define VAL _ *的不同版本的#define宏文件...並使用它來生成兩個獨立的TestSwitch()函數。否則,我必須使用#include foo001.h的#defines複製粘貼TestSwitch()作爲TestSwitch001(),然後將TestSwitch002()複製粘貼到TestSwitch001()代碼中,除了它在不同的文件中,包括的foo002.h。 – pemcode

+0

@pemcode在答案中添加了更多詳細信息。如果它們代表範圍,則不必明確定義所有5000個值。讓我知道它是否適合你。 – skypjack