C++20 学习笔记之 VA_OPT


C++20

VA_OPT 的特性与宏的可选参数(VA_ARGS)有关,经常配合起来使用,比如宏:

#define LOG(msg, ...) printf(msg, __VA_ARGS__)
LOG("hello %d\n", 0);   // => printf("hello %d", n)

如上对 LOG 宏的调用是没有问题的,但是如果我们想更灵活一点,如下的调用,就会出现问题:

LOG("hello world");  // => printf("hello world,")

可以看倒展开后多了一个逗号,这样将会导致编译错误。

现在就是VA_OPT 出场的时候了,LOG 宏可以做如下改造,以使逗号 变为可选

#define LOG(msg, ...) printf(msg __VA_OPT__(,) __VA_ARGS__)

__VA_OPT__ 回根据 __VA_ARGS_ 是否为空来决定 逗号 是否出现,因此可以解决LOG("hello world") 的调用问题。完整代码如下:

#include <stdio.h>
#define LOG(msg, ...) printf(msg __VA_OPT__(,) __VA_ARGS__)
// #define LOG(msg, ...) printf(msg, __VA_ARGS__)

int main() {
    LOG("hello world\n");   // => printf("hello world")
    LOG("hello world\n", );  // => printf("hello world")
    LOG("hello %d\n", 0);   // => printf("hello %d", n)

    // printf("Hello world",);

    return 0;
}

代码已经放在 github 上: https://github.com/ZhuBicen/Clang-in-Docker/blob/master/Tests/va_opt.cpp

另外,VA_OPT 的另外一个例子:

#define SDEF(sname, S, ...) S sname __VA_OPT__(= { __VA_ARGS__ })

SDEF(foo);           // => S foo;
SDEF(bar, 1, 2, 3);  // => S foo = { 1, 2, 3 };

最后,对于 C++ 的大多数情况,应该避免对于宏的使用