mardi 27 juin 2017

__VA_ARGS__ expansion fails if preceded by scope

I want to use __VA_ARGS__ in a macro to get the equivalent of writing several lines of if(a==b) return c.

When compiling "small sample", it fails with

identifier "name2" is undefined (Line 18)
C2065 'name3': undeclared identifier (Line 18)
C2065 'name2': undeclared identifier (Line 18)

if both USE_ENUM_CLASS and USE_VARIADIC_CONVERTER are defined.

A bit of rambling

I found information about previous versions of Visual Studio failing to expand __VA_ARGS__, but since the code works fine with an enum instead of an enum class I guess Visual Studio 2015 did fix at least some of the previous issues. In a real application I would use similar macros more then once, so this could save me a lot of lines and protect against forgetting to add code for enum values added later (adding to NAME_LIST would be sufficient).

Small sample

This causes the mentioned error. Comment out either line that defines USE_ENUM_CLASS or USE_VARIADIC_CONVERTER and it will compile.

#define NAME_LIST name1,name2,name3
#define USE_ENUM_CLASS
#define USE_VARIADIC_CONVERTER

#ifdef USE_ENUM_CLASS
enum class e
#else
enum e
#endif
{
    name1, name2, name3
};

e int_to_e(int const i)
{
#ifdef USE_VARIADIC_CONVERTER
#define POPULATE_INT_TO_E(...) if(i==static_cast<int>(e::__VA_ARGS__)) return e::__VA_ARGS__;
    POPULATE_INT_TO_E(NAME_LIST);
#else
#define POPULATE_INT_TO_E(x) if(i==static_cast<int>(e::x)) return e::x
    POPULATE_INT_TO_E(name1);
    POPULATE_INT_TO_E(name2);
    POPULATE_INT_TO_E(name3);
#endif
    throw - 1;
}

void main(void)
{
}

Further observations

The same error occurs when replacing the enum definition with

struct e
{
    enum
    {
        name1, name2, name3
    };
};

or

namespace e
{
    enum
    {
        name1, name2, name3
    };
}

or

namespace e
{
    int const name1 = 1;
    int const name2 = 2;
    int const name3 = 3;
};

Question

How can I rewrite/expand the macro to avoid these errors?

Aucun commentaire:

Enregistrer un commentaire