2011-12-16 47 views
2

我的直覺是,這是不可能的,但我不是專家。 這裏是我想要做什麼:有條件的宏文本替換

#define KEY(i) #if (i == 0) KeyClassA(arg.fieldA) 
       #elif (i == 1) KeyClassB(arg.fieldB) 
//... 
#endif 

//inside a function with given arg 
for(int i = 0; i < N; i++) { 
    Data* data = array[i]->find(KEY(i)); 
    //do things with data 
} 

該代碼顯然是僞代碼比C++代碼的,我個人不認爲這樣的事情會編譯,但我的本意應該是明確的:提供一個臨時的類對象根據數組中適當的數據結構發送到查找函數。也就是說,數組中的每個數據結構都需要一個不同的鍵匹配類。

宏文本替換看起來像試圖實現這一點的「最聰明」的方式,但我顯然歡迎任何其他想法得到這樣的工作。

+0

我不明白。你的數組究竟是什麼?你爲什麼選擇把這些特定的東西放在一個數組中?通過「鍵匹配」每個元素的不同事物,你試圖解決什麼問題? – 2011-12-16 02:37:56

+0

@KarlKnechtel沒有太具體,這是我的情況: – itchy23 2011-12-16 13:03:08

+0

@KarlKnechtel我有一個模板化的`DataStructure`類,它採用比較函數來插入和刪除數據,並接受另一個類似的函數來查找數據。發送一種數據副本來查找然後使用最初給出的比較函數來查找數據似乎是一種浪費,相比之下,只是提供了一種功能來實現這一點。 在我的實現中,我需要4個`DataStructure >`,以便進入一個數組,每個數組都按`SimpleStruct`中的字段進行排序,但不是相同的。 – itchy23 2011-12-16 13:12:22

回答

4

宏文本替換對於您的問題是無法解決的,因爲索引i僅在運行時纔可知。在編譯甚至開始之前處理宏。

如果在編譯時不知道N,那麼您將需要使用條件結構和可能的循環的一些組合。如果KeyClass* ES的數量是固定的(這似乎是這種情況),你可能能夠做這樣的事情:

void Foo(int N, Array& array, const Bar& arg) 
{ 
    if(N > 3 || N <= 0) return; 
    Data* data = array[0]->find(KeyClassA(arg.fieldA)); 
    // DoSomething(data); 
    if(N == 1) return; 
    data = array[1]->find(KeyClassB(arg.fieldB)); 
    // DoSomething(data); 
    if(N == 2) return; 
    data = array[2]->find(KeyClassC(arg.fieldC)); 
    // DoSomething(data); 
} 

放入DoSomething()功能的所有常見的代碼(最好使用一個更好的函數名),所以你不要重複自己爲N所有可能的有效值。

如果在編譯時已知N,則可以簡單地展開循環。

void Foo(Array& array, const Bar& arg) 
{ 
    Data* data = array[0]->find(KeyClassA(arg.fieldA)); 
    // DoSomething(data); 
    data = array[1]->find(KeyClassB(arg.fieldB)); 
    // DoSomething(data); 
    data = array[2]->find(KeyClassC(arg.fieldC)); 
    // DoSomething(data); 
} 

你甚至可以得到花哨模板元編程,如果你更願意拿自己展開循環,雖然這可能會爲矯枉過正你在做什麼:

// The basic idea using template specializations 
template<int i> 
struct GetKey; 

template<> 
struct GetKey<0> 
{ 
    KeyClassA From(const Bar& arg) { return KeyClassA(arg.fieldA); } 
}; 

template<> 
struct GetKey<1> 
{ 
    KeyClassB From(const Bar& arg) { return KeyClassB(arg.fieldB); } 
}; 

template<> 
struct GetKey<2> 
{ 
    KeyClassC From(const Bar& arg) { return KeyClassC(arg.fieldC); } 
}; 

template<int i, int N> 
struct Iterate 
{ 
    static void Body(Array& array, const Bar& arg) 
    { 
     Data* data = array[i]->find(GetKey<i>().From(arg)); 
     // DoSomething(data); 
     Iterate<i+1, N>::Body(array, arg); 
    } 
}; 

template<int N> 
struct Iterate<N, N> 
{ 
    static void Body(Array& array, const Bar&) {} 
}; 

void Foo(Array& array, const Bar& arg) 
{ 
    Iterate<0, 3>::Body(array, arg); 
} 
2

在這種情況下,這是不可能的,因爲i不是編譯時常量。 (不僅是編譯時常量,而且在預處理器階段是不變的)

所以你必須用普通的C++ if語句來完成。 (或一個開關)

基於我認爲你正在嘗試做的事情,使用循環會使它比它所需要的更復雜。只需將它全寫出來,並且不需要任何循環或if語句。

array[0]->find(arg.fieldA); 
array[1]->find(arg.fieldB); 
... 

(也似乎沒有做任何與Data* data

編輯:隨着新的信息。

在這種情況下,您可以將循環體放入函數調用中。像這樣的東西:

void loop_body(KeyClass &key, /* other parameters */){ 
    Data* data = array[0]->find(key); 

    // Rest of the body 
} 

而只是爲每個字段調用它。

loop_body(arg.fieldA); 
loop_body(arg.fieldB); 
... 
0

你試過#define KEY(i) i?KeyClassB(arg.fieldB):KeyClassA(arg.fieldA)

0
#define KEY(i) ((i) == 0 ? KeyClassA(arg.fieldA) : \ 
       (i) == 1 ? KeyClassB(arg.fieldB) :\ 
       ...) 

事實上,這是一個宏,真的不會給你買東西;計算仍然必須在運行時完成,因爲它取決於i的值。

這將作爲內聯函數更有意義。