Use of an overloaded operator in a scoped enum definition

103 views Asked by At

Given this code

#include <iostream>
#include <format>

enum class Enum;

constexpr Enum operator~(Enum) { return static_cast<Enum>(5); }

enum class Enum { A = 1, B = ~Enum::A }; // line 8
//                            ^^^^^^^

int main() {
    std::cout << std::format("{} and {}\n",
        static_cast<int>(Enum::B), static_cast<int>(~Enum::A));
}

is there a way to tell the compiler not to treat Enum::A on line 8 as int, but rather as of type Enum? In other words, to force the compiler to use the custom operator~(). This program outputs -2 and 5.

3

There are 3 answers

0
StoryTeller - Unslander Monica On BEST ANSWER

Not really

If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type.

If you want to execute some custom logic reliably, lift it out of the operator into a constexpr named function the accepts that the underlying type, then reuse it for both the enum declaration and the operator definition.

0
Jan Schultke On

No, there is no way to tell the compiler that. The restrictions on the type of the constant-expression after the = are laid out in [dcl.enum] p5:

  • If the underlying type is fixed (in your case, it is fixed), the type of the constant-expression is the underlying type (implicitly int in your case).
    • The underlying type must be an integral type, so you're out of luck.
  • If it isn't fixed, then it must be an integral constant expression.

In any case, B = ~Enum::A isn't valid. I was unable to find any proposal that would make this syntax valid either. The cleanest way would be to use std::to_underlying in C++23:

enum class Enum {
    A = 1,
    B = std::to_underlying(~Enum{A}) // note: A refers to 1, not Enum{1} here
};
3
Jarod42 On

Extra casting does the job:

enum class Enum {
    A = 1,
    B = static_cast<int>(~Enum(Enum::A))
};

Demo