为什么这是一个结束递归的可变参数宏?

时间:2014-10-20 11:41:31

标签: c++ visual-studio visual-c++ recursion macros

以下构造在VisualStudio 2013中编译。我刚刚创建了一个新的consoleApplication项目并且只更改了主.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

1 个答案:

答案 0 :(得分:1)

即使这是胡说八道,正如克里斯所说,这已标记为"won't fix"并且也会影响MSVC Update4(在撰写本文时)

  

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

     

Jonathan Caves   Visual C ++编译器团队

发布相关的摘录,在__VA_ARG__宏中替换时_DEFINE_ENUM_VALUES参数被视为单个令牌而不是多个令牌,因此输出

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__)

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