Switch statement support for use with std::variant.

158 views
Skip to first unread message

Parker Schuh

unread,
Nov 1, 2017, 11:59:17 AM11/1/17
to ISO C++ Standard - Future Proposals
// I was investigating a variant-like typesafe union like so:
// (Support code at the end of the message).

class MyUnionType {
 public:
  enum class TypeEnum { A_TYPE, B_TYPE, C_TYPE, };
  template <typename T>
  MyUnionType(T t) : tag_(type_enum<T>) {}

  operator TypeEnum() const { return tag_; }

 private:
  TypeEnum tag_;
};

class A { };
class B { };
class C { };

ASSIGN_ENUM_TAG(MyUnionType::TypeEnum, A, A_TYPE);
ASSIGN_ENUM_TAG(MyUnionType::TypeEnum, B, B_TYPE);
ASSIGN_ENUM_TAG(MyUnionType::TypeEnum, C, C_TYPE);

void Example() {
  MyUnionType value(B{});
  switch (value) {
   case type_enum<A>:
     printf("A\n");
     break;
   case type_enum<B>:
     printf("B\n");
     break;
   case type_enum<C>:
     printf("C\n");
     break;
  }
}

but then I thought it would be nice to be able to do this same trick with std::variant.


One could imagine this would work like so with std::variant:
void Example(const std::variant<A, B, C>& v) {
  switch(get_type_enum(v)) {
    case type_enum<A>:
      ...
      break;
    case type_enum<B>:
      ...
      break;
    // Ideally compilers would warn here -Wswitch that the third variant parameter isn't handled. Worst case this would read VARIANT_TYPE_3.
    // Using integers, this would not warn.
  }
}

I got pretty far with this:

I had a template method that would return a unique enum type from a std::varint<Ts...>, but I ran into the following problems:

- If it switch takes a type T (implicitly convertible to an integral type), it tries to convert the arguments to the integral type rather than the argument type T (which is implicitly convertible).

- And also on the other side, an inability to extract the associated Ts... from the uniquely constructed enum:
template <typename... Ts>
class A { enum Type {} };

Cannot deduce A from Type.

I feel like solving this for variant would only require passing just a wee bit more template information through the switch statement by way of:
allowing:
template <typename T> enum class {};
or,
Modifying the conversion rules in switch like so:
If the switch statement implicitly converts from T to type EnumT, then, if the case statements are implicitly convertible to T, constexpr convert them to T, and then constexpr convert the T to EnumT, otherwise convert directly to EnumT if it can. This way the template information can be passed through this intermediary struct.
or,
Allow purely inner definitions to be deducible. (Deduce T for A<T>::B where template <typename T> class A { class B {}; };  (This may have a edge-case with specializations).
or,
Type traits struct like coroutines for switch of T? This is a bit more of a stretch, and probably isn't worth it, but would allow switch(std::variant...) (as would the first one) 


// Support code for the example at the beginning of the message:

// Defaults to something that isn't an enum.

template <typename Enum, typename T, typename = std::enable_if_t<std::is_enum<Enum>::value>>
struct converted_to_enum {};

template <typename T>
class TypeEnumHelper {
 public:
  template <typename Enum, Enum = converted_to_enum<Enum, T>::value>
  constexpr operator Enum() const {
    return converted_to_enum<Enum, T>::value;
  }
};

template <typename T>
constexpr TypeEnumHelper<T> type_enum = TypeEnumHelper<T>();

#define ASSIGN_ENUM_TAG(UnionEnumType, Class, EnumTag) \
template<>  \
struct converted_to_enum<UnionEnumType, Class> { \
  static constexpr UnionEnumType value = UnionEnumType:: EnumTag; \
};

Barry Revzin

unread,
Nov 1, 2017, 12:37:43 PM11/1/17
to ISO C++ Standard - Future Proposals, parker...@gmail.com
You're looking for a language feature called pattern matching.

My understanding is that David Sankel is working with Michael Park (who wrote a pattern matching library: http://github.com/mpark/patterns) on a new draft. 

Ville Voutilainen

unread,
Nov 1, 2017, 12:46:56 PM11/1/17
to ISO C++ Standard - Future Proposals, parker...@gmail.com
On 1 November 2017 at 18:37, Barry Revzin <barry....@gmail.com> wrote:
> You're looking for a language feature called pattern matching.

Correct. Leave switch alone.

> An earlier proposal can be found here:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0095r1.html
> My understanding is that David Sankel is working with Michael Park (who
> wrote a pattern matching library: http://github.com/mpark/patterns) on a new
> draft.

The Evolution Working Group viewed the general idea of pattern
matching favorably, although we don't
know yet when it will be ready.
Reply all
Reply to author
Forward
0 new messages