Почему это не скомпилируется и как его можно реализовать так, чтобы оно выполнялось? - PullRequest
2 голосов
/ 22 апреля 2010

Вот код C ++, с которым я играюсь:

#include <iostream>
#include <vector>

#define IN ,
#define FOREACH(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i];
#define ENDFOREACH }

using namespace std;

int main()
{
    vector<int> ints;
    ints.push_back(3);
    ints.push_back(4);
    ints.push_back(5);
    ints.push_back(6);

    FOREACH(int item IN ints)
        cout << item;
    ENDFOREACH

    return 0;
}

Однако я получаю сообщение об ошибке:

макрос "FOREACH" требует 2 аргумента, но только 1 дан

Код компилируется, если я заменю IN на запятую. Как я могу получить IN вместо запятой?

Обновление: для тех, кто заинтересован, вот финальная версия, которая, если я так скажу, довольно хороша.

#include <iostream>
#include <vector>

#define in ,
#define as ,
#define FOREACH_(x,y,z) \
        y x; \
        if(z.size()) x = z[0]; \
        for(unsigned int i=0,item;i<z.size();i++,x=z[i])
#define foreach(x) FOREACH_(x)

using namespace std;

int main()
{
    vector<int> ints;
    ints.push_back(3);
    ints.push_back(4);
    ints.push_back(5);
    ints.push_back(6);

    foreach(item as int in ints)
    {
        cout << item << endl;
    }

    return 0;
}

Ответы [ 6 ]

4 голосов
/ 22 апреля 2010

Другие уже объяснили, почему он не компилируется как есть.

Чтобы это сработало, вы должны дать этому IN шанс превратиться в запятую. Для этого вы можете ввести дополнительный уровень «косвенности» в вашем макроопределении

#define IN , 
#define FOREACH_(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i]; 
#define FOREACH(x) FOREACH_(x)
#define ENDFOREACH } 

В этом случае вам придется использовать некоторую замену для запятой (например, IN) и больше не сможете явно указывать запятую. То есть теперь это

FOREACH(int item IN ints) 
    cout << item; 
ENDFOREACH 

компилируется нормально, а

FOREACH(int item, ints) 
    cout << item; 
ENDFOREACH 

нет.

3 голосов
/ 22 апреля 2010

Компилятор не раскрывает макрос IN, пока не прочитает аргументы в FOREACH.На самом деле, я думаю, что это намеренно (так что вы можете передать запятую макросу).

К сожалению, вам придется использовать FOREACH(int item, ints).

Вы также можете #define IN (сделайте это ничего), а затем используйте FOREACH(int item, IN ints), что не так приятно, но приемлемо.

Тем не менее, вы можете просто использовать STL или Boost для foreach, если вы не хотите специальносоздайте свой собственный.

1 голос
/ 22 апреля 2010
#define IN ,
#define XFOREACH(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i];
#define FOREACH(x) XFOREACH(x)
#define ENDFOREACH }

Как отмечали предыдущие авторы, препроцессор не раскрывает макросы в arglist, пока не разделит их на аргументы.Однако до тех пор, пока макрос не использует # или ##, он расширяет макросы в аргументах перед тем, как подставить их в тело макроса, поэтому дополнительная косвенная обработка делает свое дело

1 голос
/ 22 апреля 2010

Расширение для IN не происходит достаточно рано в вашем примере, но вы можете передать расширенную версию другому макросу:

#define FOREACH(x) DO_FOREACH(x)
#define DO_FOREACH(x,y) for( ... ) ...
0 голосов
/ 22 апреля 2010

Препроцессор не расширяет IN до запятой, пока не прочитает аргументы FOREACH.

Я почти уверен, что препроцессор c ++ только один проход, поэтому вам придется использовать:

FOREACH(int item, ints)
    cout << item;
ENDFOREACH
0 голосов
/ 22 апреля 2010

Проверьте BOOST_FOREACH - он делает, что вы хотите

http://www.boost.org/doc/libs/1_35_0/doc/html/foreach.html

...