4

The following construct compiles in VisualStudio 2013. I just made a new consoleApplication project and only changed the main .cpp, so you can just paste this and try it out. What it apparently does is create an end-recursive variadic macro.

#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;
}

This not only compiles, but also works only nearly as one may imagine. The output is this:

0 1 2 3 4 5 6 7 8 2

This is not a typo, the value of names::_9 is 2. And this is the case for every enum defined like this, the last value is always 2. I tested this with a whole range from 3-15 arguments.

Does anyone have an idea what's going on here?

Why is the MSVC pre-processor expanding DEFINE_ENUM_VALUE multiple times? And why, if it's intended behaviour (which I doubt), does it make the last value 2?

I also tested it with ideone, and it did fail to compile as expected, noting that everything after names::_1 wasn't part of names.

iFreilicht
  • 13,271
  • 9
  • 43
  • 74
  • Look into the preprocessed form (e.g. obtained with `gcc -C -E` if you have [GCC](http://gcc.gnu.org/)...) – Basile Starynkevitch Oct 20 '14 at 11:42
  • This doesn't work in GCC. – Rapptz Oct 20 '14 at 11:47
  • 1
    MSVC's variadic macros don't quite follow the standard, but I can't remember more details offhand. Boost.PP has fun workarounds all over the place. – chris Oct 20 '14 at 11:50
  • 1
    @BasileStarynkevitch MSVC has the `/P` option to do that. This gave some insight: `enum class names{ _0 = 0, _1, _2, _3, _4, _5, _6, _7, _8, _9 = 1+1, };` Weird – iFreilicht Oct 20 '14 at 11:53
  • [*cough* 2008](https://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement) – chris Oct 20 '14 at 12:01
  • @chris dear god, describing this as "not fixable" is horrendous. This seems like such a small bug. And I don't think I can open a new bug report, even though I'd really want to. – iFreilicht Oct 20 '14 at 12:53

1 Answers1

1

Even if this is nonsense, as chris noted this has been marked "won't fix" and also affects MSVC Update4 (at the time of writing this)

Hi: I can confirm that this is a bug with Visual C++. Unfortunately it does not meet the triage bar for the current release of Visual C++ - but we will keep the issue in our database and we will look at it again during the development phase of a future release of Visual C++.

Jonathan Caves Visual C++ Compiler Team

to post the relevant excerpts, the __VA_ARG__ parameter when replaced in the _DEFINE_ENUM_VALUES macro, is considered as a single token instead of multiple ones thus outputting

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

instead of

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

this might not be obvious when doing something like

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

but becomes evident in the example above.

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • I took the time to try and manually expand the macro all the way down, and ended up with `enum class names { _0 = 0, _1 = 1+1, };`. I was relieved when I noticed you mentioned the same expected result... I guess the macro does not do what the OP expected it to do, and this is not related to the MSVC bug. That bug just made it *look like* almost the the right thing, and masked the intrinsic coding bug. – ysap Apr 28 '16 at 21:17