Следите за расширением макросов

Я хочу отслеживать расширение макроса - сколько раз макрос был расширен и каковы аргументы, когда произошло расширение.

Например,

У меня макрос может выглядеть так:

#define mymacro(x) int x

и в моем коде есть что-то вроде этого:

mymacro(a);
mymacro(b);

в конце расширения препроцессора (о да, есть ли способ сделать конкретный макрос, который будет расширяться последним?), я хотел бы знать, сколько раз использовалось mymacro и какие аргументы были переданы. В этом случае это будет 2 раза, а аргументами будут a и b.

Я исследовал библиотеку ускорительного препроцессора. У них есть BOOST_PP_ARRAY, но я не знаю, как сделать его «статическим», чтобы использовать его позже.

Я нашел кое-что в BOOST_PP_COUNTER. Похоже, что BOOST_PP_COUNTER - это то, что может поддерживать свое состояние во фразе препроцессора. Но мне до сих пор непонятно, как делать то, что я хотел.


person Negative Zero    schedule 01.03.2012    source источник
comment
Это можно сделать, добавив в макрос строку, выводящую сообщение компилятора, если ваш компилятор это поддерживает.   -  person Collin Dauphinee    schedule 01.03.2012
comment
Можете быть более конкретными? Я использую Clang   -  person Negative Zero    schedule 01.03.2012
comment
Мне не сразу понятно, но вы говорите о прошедшей инспекции того, что происходит, и хотите, чтобы результат (то есть, с чем он был вызван и т. Д.) Был доступен во время предварительной обработки, чтобы вы могли что-то с ним сделать, верно?   -  person Matthieu M.    schedule 01.03.2012
comment
да вот что я хочу делать   -  person Negative Zero    schedule 01.03.2012
comment
Надеюсь, вы не ожидаете, что это количество будет поддерживаться во всех единицах компиляции ...   -  person Mike DeSimone    schedule 02.03.2012


Ответы (2)


Как насчет этого?

#include <iostream>

int m_counter = 0;
const char *m_arguments[32] = { 0 };

#define COUNT_M(a) m_arguments[m_counter++] = #a;
#define M(a) COUNT_M(a) int a

int main()
{
    M(x);
    M(y);

    for (int i = 0; i < m_counter; i++)
    {
        std::cout << "m_arguments[" << i << "] = \"" << m_arguments[i] << "\"\n";
    }
}
person Some programmer dude    schedule 01.03.2012
comment
хмм ... в этом случае M (x) и M (y) должны быть вызваны во время выполнения, чтобы работать. Мои маркеры - это обратные вызовы, поэтому вызывать их необязательно. Как бы то ни было, сделать это во время компиляции? - person Negative Zero; 01.03.2012

Я не совсем уверен, какова ваша конечная цель, но вы можете отслеживать количество сканирований (а не количество расширений), используя активный аргумент. Активный аргумент расширяется каждый раз, когда он просматривается препроцессором. Например,

#define EMPTY()

#define A(n) \
    A_INDIRECT EMPTY()()(BOOST_PP_INC(n)) 

#define A_INDIRECT() A

#define X(arg) arg
#define Y(arg) X(arg)
#define Z(arg) Y(arg)

   A(0)   // A_INDIRECT()(1)
X( A(0) ) // A_INDIRECT()(2)
Y( A(0) ) // A_INDIRECT()(3)
Z( A(0) ) // A_INDIRECT()(4)

Каждый вызов A подвергается разному количеству сканирований, что приводит к тому, что результаты каждый раз будут разными.

Макросы не могут повлиять на глобальное состояние. Единственный другой способ достичь какого-то состояния - использовать рекурсию. Помните, что макросы не раскрываются рекурсивно, поэтому препроцессор отслеживает это состояние. Это единственное «глобальное» состояние, на которое могут влиять макросы. Однако это может быть сложно контролировать. Макросы должны быть принудительно расширены на определенном уровне рекурсии с помощью макроса для каждого уровня, и для эффективного чтения «состояния» требуется некоторая форма двоичного поиска.

person Paul Fultz II    schedule 09.03.2012