3

Is there a way to bring all enum constants into scope? I don't mean the type, I mean the constants themselves.

struct Foo {
    enum Bar {
        A = 1, B = 2, C = 4, D = 8
    };
};

int main() {
    using E = Foo;
    int v = E::A | E::B | E::C | E::D;

    // But is it possible to instead do...
    using Foo::Bar::*; // (not real C++)
    int v = A|B|C|D; // <-- all enum constants are brought into scope
}
Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145

2 Answers2

7
// This already works, of course.
using E = Foo;
Foo::Bar v = E::A | E::B | E::C | E::D;

Well, not really, because E::A | E::B | E::C | E::D is an int and you can't implicitly convert an int to an enum.

But that's not stopping you from using 's using enum (unless you can't use C++20):

struct Foo {
    enum Bar {
        A = 1, B = 2, C = 4, D = 8
    };
};

int main() {
    using enum Foo::Bar; // (real C++20!)
    Foo::Bar v = D; 
}
Fureeish
  • 12,533
  • 4
  • 32
  • 62
  • Yes you're right about the conversion, wrote the example code too quickly without thinking :D Looks like clang 13 should support `using enum` but alas it does not :/ But yes, this is the correct answer, thanks. – Qix - MONICA WAS MISTREATED Nov 28 '21 at 10:00
  • @Qix-MONICAWASMISTREATED no problem, but are you sure you're testing with Clang 13 correctly? [Did you remember to use `-std=c++20` flag](https://godbolt.org/z/33jM6x7Yq)? – Fureeish Nov 28 '21 at 10:03
  • Yep. I'm asking the #llvm channel now about it. `clang++-13 -o test test.cc -std=c++20` should be working. – Qix - MONICA WAS MISTREATED Nov 28 '21 at 10:03
  • @Qix-MONICAWASMISTREATED interesting, I wonder what are the differences between your Clang 13 and godbolt's Clang 13, since the above snippet works there. If you come across the explanation, please mention it here :) – Fureeish Nov 28 '21 at 10:05
  • 1
    Looks like it was implemented sometime after the initial commit to the `release/13.x` branch. Pulling and building the latest HEAD of 13.x appears to include it. Neat :) Thanks again. – Qix - MONICA WAS MISTREATED Nov 28 '21 at 10:11
  • 1
    There's currently a bug in Clang, for anyone wondering - `using enum X` where `X` is an enum type nested within a struct/class, and where the constants are OR'd together *inside parenthesis* causes a segfault. https://godbolt.org/z/zWjMsz5WP – Qix - MONICA WAS MISTREATED Nov 28 '21 at 11:38
1

I misunderstood the question at first. If you are stuck pre C++20, I've used this workaround in the past.

#include <iostream>

//-----------------------------------------------------------------------------

namespace foo
{
    namespace bar
    {
        enum class Bar 
        {
            A = 1, 
            B = 2, 
            C = 4, 
            D = 8
        };

        // define some constants in namespace bar with the same values as the 
        // enum values. this will maintain typesafety of function calls.
        // but allows you to type using namespace foo::bar
        // to access these values
        
        constexpr Bar A = Bar::A;
        constexpr Bar B = Bar::B;
        constexpr Bar C = Bar::C;
        constexpr Bar D = Bar::D;
    }
}
//-----------------------------------------------------------------------------

using namespace foo::bar;

// function to show type of enum class can still be used as before
void function(const Bar enum_value)
{
    std::cout << static_cast<int>(enum_value);
}

// function for oring Bar's
Bar operator|(const Bar a, const Bar b)
{
    return static_cast<Bar>(static_cast<int>(a) | static_cast<int>(b));
}

// and a main to show it all
int main()
{
    function(A|B|C|D); // outputs 15
    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19