2015-08-06 3 views
0

Просто для небольшого фона это не тривиальное упражнение! Я работаю с Boost.Python, и, чтобы избежать множества уродливых шаблонов кода, я использую макросы для обертывания функций в классах оболочки Python, чтобы при необходимости вызвать переопределение Python для этого метода, если он существует.Использование макросов для создания списка аргументов от __VA_ARGS__

Я вареная загадку вниз к нему простейшая форма, here:

#include <iostream> 

using namespace std; 

void foo() { cout << "foo" << endl; } 
void bar(char, short, int) { cout <<"bar" << endl; } 

#define DEFINE_FUNCTION_WRAPPER(return_type, name, ...)\ 
return_type name##_wrapper(/* macro expansion */)\ 
{\ 
    return name(/* macro expansion */);\ 
}\ 

DEFINE_FUNCTION_WRAPPER(void, foo) // works! 
//DEFINE_FUNCTION_WRAPPER(void, foo, char, short, int) // knowledge insufficient 

int main() { 
    foo_wrapper(); 
    //bar_wrapper(0, 1, 2); 
} 

Хотя это, очевидно, работает foo, моя цель состоит в том, чтобы иметь DEFINE_FUNCTION_WRAPPER(void, foo, char, short, int) генерировать функцию оболочку, которая выглядит следующим образом:

void bar_wrapper(char _1, short _2, int _3) 
{ 
    return bar(_1, _2, _3); 
} 

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

Любая помощь приветствуется!

ПРИМЕЧАНИЕ: Я собираю данные на MSVC C++ 11.

+0

Если 'bar (char, short, int)' существует, какая точка 'bar_wrapper' является точным псевдонимом для него? – twentylemon

+0

Прочитайте начало сообщения. Это тривиальный пример для нетривиальной реализации. –

+0

Возможно, требуется менее простой пример. Я не вижу необходимости использовать макросы. – twentylemon

ответ

2

Предполагая, что вам действительно нужны макросы (я не слишком хорошо знаком с Boost.Python, но VARIADIC шаблонов и идеально Экспедирование в том же ключе, как это, и гораздо чист, если они применимы), вы можете использовать несколько удобных инструментов Boost.Preprocessor.

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

#include <boost/preprocessor.hpp> 

//generate "type _#" 
#define PARAMS(z,n,data) BOOST_PP_TUPLE_ELEM(n,data) _##n 

//The first variant: with parameters 
//parameters: PARAMS(z,0,(char,short,int)), PARAMS(z,1,(char,short,int)), PARAMS(z,2,(char,short,int)) 
//call: _0, _1, _2 

#define DEFINE_FUNCTION_WRAPPER_WITH_PARAMS(return_type, name, ...)\ 
return_type name##_wrapper(BOOST_PP_ENUM(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), PARAMS, (__VA_ARGS__)))\ 
{\ 
    return name(BOOST_PP_ENUM_PARAMS(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), _));\ 
} 

//The second variant: no parameters 
#define DEFINE_FUNCTION_WRAPPER_WITHOUT_PARAMS(return_type, name)\ 
return_type name##_wrapper()\ 
{\ 
    return name();\ 
} 

//choose variant based on whether more than two arguments are passed 
#define DEFINE_FUNCTION_WRAPPER(...)\ 
    BOOST_PP_IF(\ 
     BOOST_PP_GREATER(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 2), \ 
     DEFINE_FUNCTION_WRAPPER_WITH_PARAMS,\ 
     DEFINE_FUNCTION_WRAPPER_WITHOUT_PARAMS\ 
    )(__VA_ARGS__) 

//Clang output: 
//void foo_wrapper(char _0 , short _1 , int _2){ return foo(_0 , _1 , _2);} 
//int bar_wrapper(){ return bar();} 

BOOST_PP_ENUM называет данный макрос с увеличением числа, которые мы используем в PARAMS макросах обоих индексов в кортеж типов (переданному в данных) и в названии. Он также помещает запятые между расширениями, но не после последнего. Вы можете увидеть его расширение в комментариях к коду. z при необходимости можно игнорировать.

BOOST_PP_ENUM_PARAMS сохраняет работу отдельного макроса и вместо этого берет «константу» для добавления чисел в. Он также помещает запятые между расширениями. Мы используем символы подчеркивания, чтобы в итоге получилось _0, _1, _2.

+0

Похоже, что это сработает, хотя мне нужно разработать некоторые флагов компилятора, чтобы включить вызов 'BOOST_PP_VARIADIC_SIZE' на MSVC. –

+0

@cmbasnett, MSVC довольно известен тем, что имеет превосходный препроцессор. Насколько я знаю, у большинства или всех Boost.PP есть обходные пути для этого. – chris

+0

@cmbasnett, Если худшее приходит к худшему, и 'BOOST_PP_VARIADICS' не определен или что-то еще, тогда вы можете сделать макрос оболочки с количеством заданных типов и использовать' TUPLE_ELEM' с аргументом размера. – chris

Смежные вопросы