2011-12-16 2 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++, и я лично не думаю, что, как это будет компилировать, но мое намерение должно быть ясно: обеспечить временное класса к функции поиска в соответствии с соответствующей структурой данных в массиве. То есть для каждой структуры данных в массиве требуется другой класс соответствия ключей.

Macro text replacement выглядит как «самый умный» способ достичь этого, но я, очевидно, приветствую любые другие идеи, чтобы заставить что-то подобное работать.

+0

Не понимаю. Что именно в вашем массиве? Почему вы решили объединить эти конкретные вещи в массив? Какую проблему вы пытаетесь решить путем «сопоставления ключей» с каждым элементом? –

+0

@KarlKnechtel Без особой специфики, вот моя ситуация: – itchy23

+0

@KarlKnechtel У меня есть шаблонный класс DataStructure, который выполняет функцию сравнения для вставки и удаления данных и принимает другую аналогичную функцию для поиска данных. Отправка типа копии данных для поиска, а затем использования первоначально заданной функции сравнения для поиска данных кажется пустой тратой по сравнению с предоставлением только функции для этого. В моей реализации мне требуется 4 'DataStructure >', поэтому они входят в массив, каждый из которых сортируется по полям в SimpleStruct, но не в том же. – itchy23

ответ

4

Macro замещающий текст не является решением вашей проблемы, так как индекс i известен только во время выполнения. Макросы обрабатываются до начала компиляции.

Если N не известно во время компиляции, вам нужно будет использовать некоторую комбинацию условных структур и, возможно, петлю. Если число KeyClass* эс фиксированы (который, кажется, так), вы можете быть в состоянии сделать что-то вроде этого:

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); 
} 
+0

Вот как у меня это сейчас, и это уродливо (много повторяющихся команд), но я могу создать вспомогательную функцию, которая могла бы выполнять большую часть работы, которая выполняется для каждого узла данных. – itchy23

+0

@ itchy23: Правильно. Вот почему есть функция 'DoSomething()', поэтому вы можете поместить в нее весь общий код. –

+0

И да N известно во время компиляции. – itchy23

2

В этом случае это невозможно, так как i не является константой времени компиляции. (не только константа времени компиляции, но и константа на этапе препроцессора)

Таким образом, вам придется делать это, используя обычные C++ if-statements. (или переключатель)

Основываясь на том, что, как я думаю, вы пытаетесь сделать, использование цикла сделает его более сложным, чем должно быть. Просто напишите все это, и вам не нужны никакие циклы или if-statements.

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

(вы, кажется, не делать ничего с Data* data)

EDIT: С новой информацией.

В этом случае вы можете поместить тело цикла в вызов функции. Что-то вроде этого:

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

Это была очень упрощенная версия того, что мне нужно сделать. Есть еще 10+ команд, относящихся к 'data' для каждого индекса. Я отредактирую текст, чтобы показать это. – itchy23

+0

Я сейчас пытаюсь, может немного потрудиться. – itchy23

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.

Это имело бы смысл как встроенная функция.