Implicitly cast-able enum range view

68 views
Skip to first unread message

mattph...@mail.com

unread,
Mar 20, 2017, 7:55:00 AM3/20/17
to ISO C++ Standard - Future Proposals
Consider this problem:

public:
enum class State
{
Pending,
Processing,
Completed
};

State GetState() const;
void SetState(State state) const;

private:
enum class StateInternal
{
Pending,
Processing,
Completed,
Garbage,
Error
};

StateInternal m_state;

The public interface defines a subset of the object's state enum to be read and written, hiding any values that are invalid/confusing in any external context.

The problem is that the enums must either be order maintained (for casting), or involve branching to convert from one to another.

My proposed solution is a method of defining a "view" of an enum's range:

public:
enum view State : StateInternal<Pending, Completed>;

State GetState() const;
void SetState(State state) const;

private:
enum class StateInternal
{
Pending,
Processing,
Completed,
Garbage,
Error
};

The view of the enum (State) can be implicitly cast to/from its base (StateInternal), allowing for subsets of the enum to be provided to external-facing APIs only with values relevant to the context.

It could extend beyond a simple range; perhaps a way to cherry-pick valid values from the base.


Disclaimer: I wouldn't consider myself completely C++ fluent, so the terminology and/or syntax might not be the best. Please let me know if you'd like further examples.

Sean Middleditch

unread,
Mar 24, 2017, 7:14:53 PM3/24/17
to ISO C++ Standard - Future Proposals, mattph...@mail.com
On Monday, March 20, 2017 at 4:55:00 AM UTC-7, mattph...@mail.com wrote:
The problem is that the enums must either be order maintained (for casting), or involve branching to convert from one to another.

I only skimmed, but the immediate problem with anything that looks or smells like enum inheritance is slicing or up-converting. In your case, how do you convert automatically from a StateInternal value to a public State value? That's especially important in your example, since hypothetically you want to store the internal value and just provide an accessor to the public value.

I might suggest here that you actually don't _need_ the enums to be the same. Your accessor can do this for you.

  enum class State { Pending, Completed };
  enum class StateInternal { Pending, Processing, Garbage, etc. };

  State getState() const { return (state == StateInternal::Pending || _state == StateInternal::Procising) ? State::Pending : Stte::Completed; }


Alternatively, this is also the kind of thing that sum types (aka std::variant) are good for:

  struct PendingStates { enum { Pending, Processing } state; };
  struct CompletedStates { enum { Completed, Garbage, Error } state; };

  using State = std::variant<PendingStates, CompletedStates>;

Public consumers can query the variant to see when the item is pending or completed, and can decompose the variant to get any internal state.

That of course looks an awful lot prettier in languages with native support for sum types, so I personally would go for the first solution. :)

mattph...@mail.com

unread,
Mar 24, 2017, 7:58:12 PM3/24/17
to ISO C++ Standard - Future Proposals, mattph...@mail.com
No, my proposal isn't for enum inheritance, it's for restricting access (or providing a "view of") specified enum values for different contexts, without the need for branching or manual conversions requiring maintenance of two disparate but related enums.
Reply all
Reply to author
Forward
0 new messages