Развернуть шаблон Variadic в макросе Vardiadic (как извлечь имена аргументов из целевой функции)

Я борюсь со сложной, но все же простой проблемой. Допустим, у меня есть целевая функция следующим образом

void target_fnc(int arg1, double arg2)
{ /* do something here */ }

и что я хотел бы "извлечь" это имена переменных (то есть "arg1", "arg2"). Получить эту информацию для переменной с помощью некоторого предварительного процесса, например, тривиально

#define PRINTER(name) printer(#name)

void printer(const std::string& name) {cout << name << endl;}

и я также могу использовать переменные макросы в случае нескольких переменных

#define PRINTER2(names...) printer(#names)
printer(arg1,arg2)

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

template <typename ...A>
void extract(void (*)(A...))
{ printer(A...); }

Это не сработает: я получу 'A...', а не распакованные переменные, конечно... Какие-нибудь советы?

Спасибо! Примечание: я использую C++11, gcc 4.8.1

1 ответ

Существует порядок, по которому выполняются этапы компиляции, и тот, который вам нужен, не тот, который у нас есть.

Препроцессор выполняется первым; затем по окончании начинается сборка C++. Шаблонные вещи, находящиеся во время сборки, не дают им чудесной силы питать препроцессор, это наоборот.

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

Есть массивные предложения для размышления: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0255r0.pdf
или же
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1240r0.pdf
в C++, но я не знаю, когда это произойдет.

В противном случае вы можете попробовать такие вещи, как
http://pfultz2.com/blog/2012/07/31/reflection-in-under-100-lines/

REFLECTABLE
(
    (const char *) name,
    (int) age
)

int main()
{
    Person p("Tom", 82);
    print_fields(p);
    return 0;
}

CPP - это только система копирования и вставки текста. Это не предназначено, чтобы сделать такую ​​магию. На самом деле, он выполняет только глупые операции "Когда видишь X, поставь Y ".

В вашем случае, если вы попытаетесь перебрать пакет с переменными значениями:

inline void print(const std::string& name) { std::cout << name << std::endl; }

#define PRINT(name) print(#name)

//Base case:
void extract() {}

//Recursive case:
template<typename HEAD , typename... TAIL>
void extract(const HEAD& head , const TAIL& tail...)
{
    PRINT(head);

    extract(tail...);
}

Вы получаете только:

голова
голова
голова
голова
...

Ответ таков: избегайте использования CPP для глупых вещей, используйте его только для #ifdef #endif Заголовок охранников и портативный сборник.

Обратите внимание, что GET_GREATHER(x,y) ((x) > (y) ? (x) : (y)) как макросы не включены. C++ имеет с самого начала свою историю мощный инструмент для избежания макросов: встроенные функции