Макрос C / C ++, расширяющийся до аргумента, аргумент в виде строки - PullRequest
8 голосов
/ 22 декабря 2011

У меня есть много переменных, имена которых совпадают с элементами в документе технической спецификации, поэтому строковая версия имени также полезна.

Я часто использую такой макрос:

#define MACRO(a) a, #a

Типичное использование:

void someFunction(int a, const char *name);

someFunction(MACRO(meaningfully_named_variable));

Мой вопрос тройной:

  • Есть ли лучший способ сделать это?
  • Имеется ли подобный макрос в Boost или других библиотеках?
  • Если нет, как я могу уточнить и переименовать это, чтобы сделать его понятным и полезным?

Редактировать Я должен был сказать, что вышеизложенное является минимальным примером. Функция может иметь другие параметры, а именованная сущность может быть элементом данных или, возможно, даже самой функцией.

Еще одним расширением, которое я рассматриваю для C ++, является класс NamedRef, который может получать содержимое макроса.

template <typename T>
struct NamedRef
{
    NamedRef(T *t, const char *name) : t(t), name(name) { }
    T *t;
    const char *name;
};

template <typename T>
NamedRef<T> namedRef(T &t, const char *name)
{
    return NamedRef<T>(&t, name);
}

#define WITH_NAME(a) a, #a

// more sophisticated usage example
void otherFunction(double, NamedRef<int>, bool);

otherFunction(0.0, namedRef(object.WITH_NAME(meaningful_member_name)), false);

Ответы [ 4 ]

5 голосов
/ 22 декабря 2011

Вы можете сделать шаг вперед:

#define SOMEFUNCTION(a) somefunction(a, #a)

Однако это полезно, только если вы вызываете одну и ту же функцию много. В противном случае, я не думаю, что есть лучший способ, чем ваш пример. Конечно, вы должны изменить имя макроса на что-то более значимое, например ARGUMENTS или что-то еще.

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

Как ответил Джесси,

Вы можете написать так:

void function1(int a, const char* name)
{
    cout << "a: " << a << endl;
    cout << "name: " << name << endl;
}

void function2(double d, const char* name, const char *str)
{
    cout << "d: " << d << endl;
    cout << "name: " << name << endl;
    cout << "str: " << str << endl;
}

#define MACRO(functionName, a) functionName(a, #a)
#define MACRO2(functionName, a, ...) functionName(a, #a, __VA_ARGS__)

int main()
{
    int a = 10;
    MACRO(function1, a);
    double d = 10.5;
    MACRO2(function2, d, "Hello world");
    return 0;
}

Если вам нужно передать больше аргументов, вы можете использовать MACRO2, который использует переменные аргументы. Вы должны будете передать имя функции соответственно.

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

Вы, вероятно, обнаружите, что XMACRO s полезны для такой работы.

0 голосов
/ 22 декабря 2011
#define someFunction(a)  if (1) stringized_someFunction((a), #a ); else (void)0
void stringized_someFunction(int a, const char* name);

Материал if (1) оборачивает макрос так, что он не будет (обычно) связываться с циклами, ветвями, операторами if и т. Д.

Затем вы бы назвали свою функцию так:

int r = 4;
someFunction(r);

Вы действительно добавляете только одну дополнительную строку для каждого «объявления функции». Если препроцессор C допускает несколько шагов, вы можете объединить все в один, но, увы, это не так.

Я забыл, потому что, надеюсь, очевидно, что вам нужно написать свою функцию:

void stringized_someFunction(int a, const char* name)
{
  // Do stuff here
}

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

...