C 宏的可选参数

新手上路,请多包涵

有没有办法用 C++ 宏获取可选参数?某种重载也会很好。

原文由 Cenoc 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 552
2 个回答

这是一种方法。它使用参数列表两次,首先形成辅助宏的名称,然后将参数传递给辅助宏。它使用标准技巧来计算宏的参数数量。

 enum
{
    plain = 0,
    bold = 1,
    italic = 2
};

void PrintString(const char* message, int size, int style)
{
}

#define PRINT_STRING_1_ARGS(message)              PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size)        PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)

#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
    GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
                PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )

#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

int main(int argc, char * const argv[])
{
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 18);
    PRINT_STRING("Hello, World!", 18, bold);

    return 0;
}

这使宏的调用者更容易,而不是编写者。

原文由 Derek Ledbetter 发布,翻译遵循 CC BY-SA 2.5 许可协议

不是直接回答问题,而是使用与 David Sorkovsky 回答相同的技巧,并给出了如何构建复杂宏的清晰示例。

只需用 g++ -E test.cpp -o test && cat test 编译它:

 // #define GET_FIRST_ARG_0_ARGS(default) (default)
// #define GET_FIRST_ARG_1_ARGS(default, a) (a)
// #define GET_FIRST_ARG_2_ARGS(default, a, b) (a)
// #define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a)
// #define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a)
#define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro

#define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \
        ,##__VA_ARGS__, \
        GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \
    )

"0,"; GET_FIRST_ARG(0);
"0,1"; GET_FIRST_ARG(0,1);
"0,1,2"; GET_FIRST_ARG(0,1,2);
"0,1,2,3"; GET_FIRST_ARG(0,1,2,3);
"0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4);

要查看输出:

 # 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/x86_64-linux-gnu/include/stdc-predef.h" 1 3
# 1 "<command-line>" 2
# 1 "test.cpp"
# 16 "test.cpp"
"0,"; GET_FIRST_ARG_0_ARGS(0);
"0,1"; GET_FIRST_ARG_1_ARGS(0, 1);
"0,1,2"; GET_FIRST_ARG_2_ARGS(0, 1,2);
"0,1,2,3"; GET_FIRST_ARG_3_ARGS(0, 1,2,3);
"0,1,2,3,4"; GET_FIRST_ARG_4_ARGS(0, 1,2,3,4);

现在,一个完整的工作程序将是:

 #include <iostream>

#define GET_FIRST_ARG_0_ARGS(default) (default)
#define GET_FIRST_ARG_1_ARGS(default, a) (a)
#define GET_FIRST_ARG_2_ARGS(default, a, b) (a)
#define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a)
#define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a)
#define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro

#define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \
        ,##__VA_ARGS__, \
        GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \
        GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \
    )

int main(int argc, char const *argv[]) {
    "0,"; GET_FIRST_ARG(0);
    "0,1"; GET_FIRST_ARG(0,1);
    "0,1,2"; GET_FIRST_ARG(0,1,2);
    "0,1,2,3"; GET_FIRST_ARG(0,1,2,3);
    "0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4);

    std::cerr << "0, == " << GET_FIRST_ARG(0) << std::endl;
    std::cerr << "0,1 == " << GET_FIRST_ARG(0,1) << std::endl;
    std::cerr << "0,1,2 == " << GET_FIRST_ARG(0,1,2) << std::endl;
    std::cerr << "0,1,2,3 == " << GET_FIRST_ARG(0,1,2,3) << std::endl;
    std::cerr << "0,1,2,3,4 == " << GET_FIRST_ARG(0,1,2,3,4) << std::endl;
    return 0;
}

通过使用 g++ test.cpp -o test && ./test 编译将输出以下内容:

 0, == 0
0,1 == 1
0,1,2 == 1
0,1,2,3 == 1
0,1,2,3,4 == 1

注意:当 a 不是整数时,请务必在宏内容周围使用 () 作为 #define GET_FIRST_ARG_1_ARGS(default, a) (a) 以不中断不明确的表达式。

第二个参数的额外宏:

 #define GET_SECOND_ARG_0_ARGS(default) (default)
#define GET_SECOND_ARG_1_ARGS(default, a) (default)
#define GET_SECOND_ARG_2_ARGS(default, a, b) (b)
#define GET_SECOND_ARG_3_ARGS(default, a, b, c) (b)
#define GET_SECOND_ARG_4_ARGS(default, a, b, c, d) (b)
#define GET_SECOND_ARG_MACROS(default, a, b, c, d, macro, ...) macro

#define GET_SECOND_ARG(default, ...) GET_SECOND_ARG_MACROS( \
        ,##__VA_ARGS__, \
        GET_SECOND_ARG_4_ARGS(default, __VA_ARGS__), \
        GET_SECOND_ARG_3_ARGS(default, __VA_ARGS__), \
        GET_SECOND_ARG_2_ARGS(default, __VA_ARGS__), \
        GET_SECOND_ARG_1_ARGS(default, __VA_ARGS__), \
        GET_SECOND_ARG_0_ARGS(default, ##__VA_ARGS__), \
    )

原文由 user 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题