【问题标题】:Allowing initializer lists inside of a macro允许宏内部的初始化列表
【发布时间】:2020-04-14 08:07:21
【问题描述】:

在我正在处理的一个项目中,有一个记录表达式的宏。我的任务是添加向其中传递多个值并让每个打印件单独打印的功能。
通过 1 到 5 个参数,我设法让这项工作相对容易。它甚至可以很好地传递给一个函数。

我现在遇到的问题是初始化列表不再起作用。该项目使用可变参数来允许在其内部进行数组初始化,例如func(std::vector<int>{0, 1, 0, 1})。由于我已经实现了多 arg 的东西,因此由于逗号而不再起作用。

我知道我可以做func((std::vector<int>{0, 1, 0, 1})),这会很好,但我知道这不会被喜欢作为一种解决方法。有没有办法让这些在没有额外括号的情况下工作,或者在需要时添加额外的括号?

这里有一些相关的 sn-ps:


// Intermediate macro "chooser"
#define func_x(x, A, B, C, D, E, Func, ...) Func

// Macro to be called and used by user
// First param must be blank to allow for 0 argument function
#define func(...) func_x(, ##__VA_ARGS__, \
  func_5(__VA_ARGS__), func_4(__VA_ARGS__), func_3(__VA_ARGS__), \
  func_2(__VA_ARGS__), func_1(__VA_ARGS__), func_0())

// Macros for 1 through 5 args, calls the func_VA macro.
#define func_1(A1) func_VA(A1)
#define func_2(A1, A2) func_1(A1), func_VA(A2)
#define func_3(A1, A2, A3) func_2(A1, A2), func_VA(A3)
#define func_4(A1, A2, A3, A4) func_3(A1, A2, A3), func_VA(A4)
#define func_5(A1, A2, A3, A4, A5) func_4(A1, A2, A3, A4), func_VA(A5)

// Prints expression and type
// We use a variadic macro to support commas inside expressions (e.g.
// initializer lists):
#define func_VA(...)                                                  \
  func_macro::DebugOutput(__FILE__, __LINE__, __func__, #__VA_ARGS__) \
      .print(func_macro::type_name<decltype(__VA_ARGS__)>(), (__VA_ARGS__))

func(std::vector<int>{0, 1, 0, 1});
// Errors

func((std::vector<int>{0, 1, 0, 1}));
// Works, but also prints the () when logging so not ideal. Better than nothing though.

我一直在尝试在宏的某些部分周围插入括号以尝试修复此问题,但无济于事。喜欢#define func_1(A1) func_VA((A1)) 或类似的。

编辑:我已经取得了一些进展

如果我像你想象的那样调用func_1(std::vector&lt;int&gt;{0, 1, 0, 1});,现在可以像#define func_1(...) func_VA(__VA_ARGS__) 一样声明func_1

我制作了一个“包装器”宏,它返回(__VA_ARGS__),这允许宏与列表初始化一起正常工作,尽管字符串版本确实有额外的括号。虽然我不能让它以这样的方式工作,这样你(作为用户)就不必在你的数组上调用包装器(这比把括号放在你自己的位置上更难)。

【问题讨论】:

  • 为什么要在参数数量上重载宏?只是#define func(...) func_macro::DebugOutput(__FILE__, ......)?
  • @KamilCuk 我不完全确定这是否适用于 DebugOutput 类的工作方式。但也许我遗漏了什么,你能进一步启发我吗?
  • #define func(...) func_macro::DebugOutput(__FILE__, __LINE__, __func__, ##__VA_ARGS__).print(func_macro::type_name&lt;decltype(__VA_ARGS__)&gt;(), (__VA_ARGS__)) 我完全不知道 DebugOutput 是如何工作的,不是它是如何工作的,你没有展示它。
  • @KamilCuk 是的,IK。它使用 VA 在内部启用逗号以进行初始化,如上面func_VA 评论中所述,老实说,我并不完全确定它是如何做到这一点的。纵观历史,除了使用 ... 而不是普通的变量之外,没有其他细节。
  • It uses VA - 在这种情况下“VA”是什么?你想在 dbg(std::vector&lt;int&gt;{0, 1, 0, 1}, std::vector&lt;int&gt;{0, 1, 0, 1}); 这样的事情上发生什么?

标签: c++ preprocessor


【解决方案1】:

如果您可以将DebugOutput::print 更改为可变参数模板,您可能会执行以下操作:

#define func(...)                                                     \
  func_macro::DebugOutput{__FILE__, __LINE__, __func__, #__VA_ARGS__} \
      .print(__VA_ARGS__)


namespace func_macro
{

struct DebugOutput
{
    const char* filename = nullptr;
    int line = 0;
    const char* funcname = nullptr;
    const char* argsString = nullptr;

    template <typename ... Ts>
    void print(const Ts&... args) const
    {
        std::cout << filename << ":" << line << " in " << funcname << std::endl;
        std::cout << "func(" << argsString << ")\n";

        ((std::cout << typeid(args).name() << ": " << args << std::endl), ...);
    }
};

}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多