Развернуть шаблон 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++ имеет с самого начала свою историю мощный инструмент для избежания макросов: встроенные функции