可变参数宏和参数包扩展

时间:2019-02-23 08:31:37

标签: c++ c++11

在下面的示例代码中,我想使用带有变量参数的MACRO_EXPANSION{...}来构造EnumTypes对象的列表。但是,我无法使这个想法起作用。 (PS。代码结构可能看起来不太好,但是我需要它:))

#include <iostream>
#include <utility>
#include <initializer_list>

enum class EnumOneTypes {
  One0,
  One1
};

enum class EnumTwoTypes {
  Two0,
  Two1
};

struct EnumTypes {
  EnumOneTypes one;
  EnumTwoTypes two;
};

void do_something(std::initializer_list<EnumTypes> il) {
    std::cout << "Do something" << std::endl;
}

// Need this struct to forward arguments
struct Register {
  template <typename... TArgs>
  Register(TArgs&&... args) {
    do_something(std::forward<TArgs>(args)...);
    //also do other things after do_something, omit here
    // ...
  }
};

// Use this macro to define global static objects
#define MACRO_EXPANSION(name, ...) \
  static struct Register name(__VA_ARGS__)

MACRO_EXPANSION(
  register_two,
  {EnumOneTypes::One0, EnumTwoTypes::Two0},
  {EnumOneTypes::One1, EnumTwoTypes::Two1}
);

MACRO_EXPANSION(
  register_three,
  {EnumOneTypes::One0, EnumTwoTypes::Two0},
  {EnumOneTypes::One1, EnumTwoTypes::Two1},
  {EnumOneTypes::One0, EnumTwoTypes::Two1}
);

int main() {
  std::cout << "Test the usage of this macro" << std::endl;
  return 0;
}

1 个答案:

答案 0 :(得分:2)

  1. 可变参数模板不能自动为std::initializer_list。因此,让我们用方括号将可变参数括起来。
struct Register {
  template <typename... TArgs>
  Register(TArgs&&... args) {
    do_something({std::forward<TArgs>(args)...}); // Make params to be initializer List
    //also do other things after do_something, omit here
    // ...
  }
};
  1. 由于Register构造函数是模板化的,因此似乎编译器无法推断{EnumOneTypes::One0, EnumTwoTypes::Two0}属于哪种类型。因此,让我们将其类型指定为:
MACRO_EXPANSION(
  register_two,
  EnumTypes{EnumOneTypes::One0, EnumTwoTypes::Two0},
  EnumTypes{EnumOneTypes::One1, EnumTwoTypes::Two1}
);

应用这两个方法之后,它会成功编译并运行输出:

Do something
Do something
Test the usage of this macro

我在godbolt中进行了测试。