Условная замена макротекста - PullRequest
2 голосов
/ 16 декабря 2011

У меня такое чувство, что это невозможно, но я не эксперт. Вот что я хотел бы сделать:

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

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

Ответы [ 4 ]

4 голосов
/ 16 декабря 2011

Замена макрокоманды не является решением вашей проблемы, поскольку индекс 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);
}
2 голосов
/ 16 декабря 2011

В этом случае это все равно невозможно, потому что 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 голосов
/ 16 декабря 2011
#define KEY(i) ((i) == 0 ? KeyClassA(arg.fieldA) : \
                (i) == 1 ? KeyClassB(arg.fieldB) :\
                ...)

Тот факт, что это макрос, на самом деле ничего не покупает;вычисление все еще должно быть выполнено во время выполнения, потому что оно зависит от значения i.

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

0 голосов
/ 16 декабря 2011

вы пробовали #define KEY(i) i?KeyClassB(arg.fieldB):KeyClassA(arg.fieldA)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...