用于生成方法和转发参数的C ++或宏魔术

时间:2017-06-26 11:07:03

标签: c++ c++11 macros

我想创建一个神奇的宏,或任何会产生这样的东西:

MAGICAL_MACRO(return_type, method_name, ...)

应该像这样工作:

MAGICAL_MACRO(void, Foo, int a, int b)

- >

virtual void Foo(int a, int b) 
{
    _obj->Foo(a, b);
}

这可能吗?恐怕不是。

3 个答案:

答案 0 :(得分:5)

两个问题:您是否对MAGIC_MACRO的参数略有不同的语法?您可以使用Boost.Preprocessor仅限标头的库吗?

如果两个答案都是"是",我有一个解决方案:

#define MAGICAL_MACRO(Type, Name, ...) \
  virtual Type Name(MAGICAL_GENERATE_PARAMETERS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))) {\
    _obj->Name(MAGICAL_GENERATE_ARGUMENTS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))); \
  }

#define MAGICAL_GENERATE_PARAMETERS(Args) \
  BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MAGICAL_MAKE_PARAMETER, %%, Args))

#define MAGICAL_GENERATE_ARGUMENTS(Args) \
  BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MAGICAL_MAKE_ARGUMENT, %%, Args))

#define MAGICAL_MAKE_PARAMETER(s, Unused, Arg) \
  BOOST_PP_TUPLE_ELEM(2, 0, Arg) BOOST_PP_TUPLE_ELEM(2, 1, Arg)

#define MAGICAL_MAKE_ARGUMENT(s, Unused, Arg) \
  BOOST_PP_TUPLE_ELEM(2, 1, Arg)

用法如下:

MAGICAL_MACRO(void, Foo, (int, a), (int, b))

[Live example]

宏定义中使用的%%只是我指示的方式"不使用此值。"你可以在那里使用其他任何东西(除非它包含逗号)。

只要所涉及的类型没有拼写逗号,上述解决方案就会起作用。如果是,请为它们引入类型别名(typedefusing)。请注意, 可以在预处理器魔术本身内解决这个问题,但它使已经很难看的代码变得复杂。

答案 1 :(得分:4)

如果您不介意更改宏参数的语法,可以使用以下技巧滥用声明语法:

#define MAGICAL_MACRO(return_type, method_name, ...) \
    virtual return_type method_name(__VA_ARGS__)
    { \
        _obj->method_name(__VA_ARGS__); \
    }

MAGICAL_MACRO(void, foo, int(a), int(b))

那将扩展为:

virtual void foo(int(a), int(b))
{
    _obj->foo(int(a), int(b));
}

void func(int(a), int(b))完全等同于void func(int a, int b)

额外的强制转换(或构造函数调用取决于参数类型)是丑陋的,但GCC和Clang(带-O0)似乎都忽略了它们,不仅对于原始类型/ POD,而且对于非POD类即使他们的副本构造函数有副作用:

#include <iostream>

struct A
{
    int x;
    A(int value) : x(value) {}
    A(const A &o)
    {
        x = o.x;
        std::cout << "copy";
    }
};

void func(A a)
{
    std::cout << a.x << '\n';
}

void func1(A a)
{
    func(a);
}
void func2(A a)
{
    func(A(a));
}

int main()
{
    func1(1); // prints `copy1`
    func2(2); // prints `copy2`
}

答案 2 :(得分:2)

以下代码适用于您所要求的最多1024个参数以及不使用使用其他内容(如boost)。它定义了一个this.axios.post('url', this.form).then(...和一个EVAL(...)宏来进行递归,并为每个迭代使用宏MAP(m, first, ...)和下一个参数m

主要是从C Pre-Processor Magic复制的。那里的解释也很棒。您也可以在此git repository下载first这样的辅助宏,实际代码中也有很多解释。它是可变的,所以它需要你想要的参数数量。

但是我更改了EVAL(...)FIRST宏,因为它使用了Gnu扩展名,就像我在源代码中复制了它一样。

要将SECOND等参数拆分为int aint我使用this answer from SO

你的宏将是:

a

示例和限制:

#define MAGICAL_MACRO(return_type, method_name, ...) \
   virtual return_type method_name(__VA_ARGS__) \
   { \
      return _obj->method_name(EVAL(MAP(TYPE_NAME, __VA_ARGS__))); \
   }

需要所有其他宏,请注意需要在每个宏中定义类型拆分:

MAGICAL_MACRO(void, FOO, int a, double b, char c);
--> virtual void FOO(int a, double b, char c) { return _obj->FOO(a , b , c); };

MAGICAL_MACRO(int, FOO, int a, double b, char c);
-->  virtual int FOO(int a, double b, char c) { return _obj->FOO(a , b , c); } ;

MAGICAL_MACRO(void, FOO, int* a, double* b, char* c);
--> virtual void* FOO(int* a, double* b, char* c) { return _obj->FOO(* a , * b , * c); };
/* maybe not what you want: pointer are dereferenced */