使用宏从__VA_ARGS__生成参数列表

Using macros to generate argument list from __VA_ARGS__

本文关键字:参数 列表 ARGS VA      更新时间:2023-10-16

只是为了了解一点背景知识,这不是一个简单的练习!我在和Boost合作。为了避免大量丑陋的样板代码,我使用宏将函数包装在Python包装器类中,以便在方法存在的情况下选择性地调用Python重写。

我把这个难题归结为最简单的形式,在这里:

#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.

假设您确实需要宏(我不太熟悉Boost)。Python,但可变模板和完美转发与此相同,如果适用的话更干净),您可以使用几个方便的Boost。预处理工具。

需要注意的是,宏末尾的省略号必须至少传递一个参数;它不可能是零。为了解决这个问题,您必须在此过程中至少放弃一个参数名称。我选择让宏根据是否获得任何与参数相关的参数来填充该省略号,从另外两个参数中选择一个。

#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。