为什么这是一个结束递归变量宏

Why is this an end-recursive variadic macro?

本文关键字:结束 一个 递归 变量 为什么      更新时间:2023-10-16

以下构造在VisualStudio2013中编译。我刚做了一个新的consoleApplication项目,只更改了main.cpp,所以你可以粘贴它并试用它。它所做的显然是创建一个结束递归的可变宏。

#include "stdafx.h"
#include <iostream>
using namespace std;
#define DEFINE_ENUM_VALUE(name, i) name = i,
#define _DEFINE_ENUM_VALUES(i, name, ...) DEFINE_ENUM_VALUE(name, i+1)
#define DEFINE_ENUM_VALUES(enum_name, name, ...) enum class enum_name{ 
    DEFINE_ENUM_VALUE(name, 0) _DEFINE_ENUM_VALUES(1, __VA_ARGS__) 
};
DEFINE_ENUM_VALUES(names, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9)
int _tmain(int argc, _TCHAR* argv[])
{
    cout << (int)names::_0 << ' ';
    cout << (int)names::_1 << ' ';
    cout << (int)names::_2 << ' ';
    cout << (int)names::_3 << ' ';
    cout << (int)names::_4 << ' ';
    cout << (int)names::_5 << ' ';
    cout << (int)names::_6 << ' ';
    cout << (int)names::_7 << ' ';
    cout << (int)names::_8 << ' ';
    cout << (int)names::_9 << ' ';
    return 0;
}

这不仅可以编译,而且几乎可以像人们想象的那样工作。输出是这样的:

0 1 2 3 4 5 6 7 8 2

这是而不是打字错误,names::_9的值为2。对于这样定义的每个枚举,最后一个值总是2。我用3-15个论点进行了测试。

有人知道这里发生了什么吗?

为什么MSVC预处理器多次扩展DEFINE_ENUM_VALUE?为什么,如果这是预期行为(我对此表示怀疑),它会使最后一个值为2?

我还用ideone测试了它,但它确实无法按预期编译,注意到names::_1之后的所有内容都不是names的一部分。

即使这是无稽之谈,正如chris所指出的,这已经被标记为"不会修复";并且还影响MSVC Update4(在撰写本文时)

嗨:我可以确认这是Visual C++的一个错误。不幸的是,它不符合Visual C++当前版本的分类标准,但我们将把这个问题保留在数据库中,并将在未来Visual C++版本的开发阶段再次研究它。

乔纳森·卡维斯Visual C++编译器团队

为了发布相关摘录,在_DEFINE_ENUM_VALUES宏中替换__VA_ARG__参数时,会将其视为单个令牌,而不是多个令牌,从而输出

enum class names{ _0 = 0, _1, _2, _3, _4, _5, _6, _7, _8, _9 = 1+1, };
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is a single token
                                                             for MSVC

而不是

enum class names{ _0 = 0, _1 = 1 +1, };

这在做这样的事情时可能并不明显

#define printf_macro(format_string, ...) printf(format_string, __VA_ARGS__)

但是在上面的例子中变得明显。