Topic: Switch statement support for use with std::variant.


Author: Parker Schuh <parker.schuh@gmail.com>
Date: Wed, 1 Nov 2017 08:59:17 -0700 (PDT)
Raw View
------=_Part_10903_1031879791.1509551957293
Content-Type: multipart/alternative;
 boundary="----=_Part_10904_784088170.1509551957293"

------=_Part_10904_784088170.1509551957293
Content-Type: text/plain; charset="UTF-8"

// 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; \
};

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e0683c7a-3db4-4ee6-b10b-649d13c94cd5%40isocpp.org.

------=_Part_10904_784088170.1509551957293
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"prettyprint" style=3D"background-color: rgb(=
250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bord=
er-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div cla=
ss=3D"subprettyprint"><div class=3D"subprettyprint" style=3D""><div class=
=3D"subprettyprint">// I was investigating a variant-like typesafe union li=
ke so:<br><div class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">// (=
Support code at the end of the message).<br><br class=3D"Apple-interchange-=
newline">class MyUnionType {</div><div class=3D"subprettyprint" style=3D"co=
lor: rgb(0, 0, 0);">=C2=A0public:</div><div class=3D"subprettyprint" style=
=3D"color: rgb(0, 0, 0);">=C2=A0 enum class TypeEnum {=C2=A0<span style=3D"=
font-family: Arial, Helvetica, sans-serif;">A_TYPE,=C2=A0</span><span style=
=3D"font-family: Arial, Helvetica, sans-serif;">B_TYPE,=C2=A0</span><span s=
tyle=3D"font-family: Arial, Helvetica, sans-serif;">C_TYPE,=C2=A0</span><sp=
an style=3D"font-family: Arial, Helvetica, sans-serif;">};</span></div><div=
 class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);"><div class=3D"subp=
rettyprint">=C2=A0 template &lt;typename T&gt;</div><div class=3D"subpretty=
print">=C2=A0 MyUnionType(T t) : tag_(type_enum&lt;T&gt;) {}</div></div><di=
v class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);"><br></div><div cl=
ass=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0 operator TypeE=
num() const { return tag_; }</div><div class=3D"subprettyprint" style=3D"co=
lor: rgb(0, 0, 0);"><br></div><div class=3D"subprettyprint" style=3D"color:=
 rgb(0, 0, 0);">=C2=A0private:</div><div class=3D"subprettyprint" style=3D"=
color: rgb(0, 0, 0);">=C2=A0 TypeEnum tag_;</div><div class=3D"subprettypri=
nt" style=3D"color: rgb(0, 0, 0);">};</div><div class=3D"subprettyprint" st=
yle=3D"color: rgb(0, 0, 0);"><br></div><div class=3D"subprettyprint" style=
=3D"color: rgb(0, 0, 0);">class A { };</div><div class=3D"subprettyprint" s=
tyle=3D"color: rgb(0, 0, 0);">class B { };</div><div class=3D"subprettyprin=
t" style=3D"color: rgb(0, 0, 0);">class C { };</div><div class=3D"subpretty=
print" style=3D"color: rgb(0, 0, 0);"><br></div><div class=3D"subprettyprin=
t" style=3D"color: rgb(0, 0, 0);">ASSIGN_ENUM_TAG(MyUnionType::TypeEnum, A,=
 A_TYPE);</div><div class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);"=
>ASSIGN_ENUM_TAG(MyUnionType::TypeEnum, B, B_TYPE);</div><div class=3D"subp=
rettyprint" style=3D"color: rgb(0, 0, 0);">ASSIGN_ENUM_TAG(MyUnionType::Typ=
eEnum, C, C_TYPE);</div><br><div class=3D"subprettyprint" style=3D"color: r=
gb(0, 0, 0);">void Example() {</div><div class=3D"subprettyprint" style=3D"=
color: rgb(0, 0, 0);">=C2=A0 MyUnionType value(B{});</div><div class=3D"sub=
prettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0 switch (value) {</div><d=
iv class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0 =C2=A0cas=
e type_enum&lt;A&gt;:</div><div class=3D"subprettyprint" style=3D"color: rg=
b(0, 0, 0);">=C2=A0 =C2=A0 =C2=A0printf(&quot;A\n&quot;);</div><div class=
=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0 =C2=A0 =C2=A0brea=
k;</div><div class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0=
 =C2=A0case type_enum&lt;B&gt;:</div><div class=3D"subprettyprint" style=3D=
"color: rgb(0, 0, 0);">=C2=A0 =C2=A0 =C2=A0printf(&quot;B\n&quot;);</div><d=
iv class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0 =C2=A0 =
=C2=A0break;</div><div class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0=
);">=C2=A0 =C2=A0case type_enum&lt;C&gt;:</div><div class=3D"subprettyprint=
" style=3D"color: rgb(0, 0, 0);">=C2=A0 =C2=A0 =C2=A0printf(&quot;C\n&quot;=
);</div><div class=3D"subprettyprint" style=3D"color: rgb(0, 0, 0);">=C2=A0=
 =C2=A0 =C2=A0break;</div><div class=3D"subprettyprint" style=3D"color: rgb=
(0, 0, 0);">=C2=A0 }</div><div class=3D"subprettyprint" style=3D"color: rgb=
(0, 0, 0);">}</div></div></div></div></code></div><div class=3D"prettyprint=
" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187=
, 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><co=
de class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"font-=
family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);=
"><br>but then I thought it would be nice to be able to do this same trick =
with std::variant.</span><br style=3D"font-family: Arial, Helvetica, sans-s=
erif; background-color: rgb(255, 255, 255);"><br style=3D"font-family: Aria=
l, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span styl=
e=3D"font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, =
255, 255);">One could imagine this would work like so with std::variant:</s=
pan><br style=3D"font-family: Arial, Helvetica, sans-serif; background-colo=
r: rgb(255, 255, 255);"><div class=3D"prettyprint" style=3D"border-width: 1=
px; border-style: solid; border-color: rgb(187, 187, 187); font-family: Ari=
al, Helvetica, sans-serif; word-wrap: break-word;"><code class=3D"prettypri=
nt"><div class=3D"subprettyprint"><font color=3D"#660066">void Example(cons=
t std::variant&lt;A, B, C&gt;&amp; v) {<br>=C2=A0 switch(get_type_enum(v)) =
{<br>=C2=A0 =C2=A0 case type_enum&lt;A&gt;:<br>=C2=A0 =C2=A0 =C2=A0 ...<br>=
=C2=A0 =C2=A0 =C2=A0 break;<br>=C2=A0 =C2=A0 case type_enum&lt;B&gt;:<br>=
=C2=A0 =C2=A0 =C2=A0 ...<br>=C2=A0 =C2=A0 =C2=A0 break;<br>=C2=A0 =C2=A0 //=
 Ideally compilers would warn here -Wswitch that the third variant paramete=
r isn&#39;t handled. Worst case this would read VARIANT_TYPE_3.<br>=C2=A0 =
=C2=A0 // Using integers, this would not warn.<br>=C2=A0 }<br>}</font></div=
></code></div></div></code></div><br>I got pretty far with this:<br><br>I h=
ad a template method that would return a unique enum type from a std::varin=
t&lt;Ts...&gt;, but I ran into the following problems:<br><br>- If it switc=
h 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).<br><br>- And also on the other side, an =
inability to extract the associated Ts... from the uniquely constructed enu=
m:<br>template &lt;typename... Ts&gt;<br>class A { enum Type {} };<br><br>C=
annot deduce A from Type.<br><br>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:<br>allowing:<br>template &lt;typename T&gt; enu=
m class {};<br>or,<br>Modifying the conversion rules in switch like so:<br>=
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 directl=
y to EnumT if it can. This way the template information can be passed throu=
gh this intermediary struct.<br>or,<div>Allow purely inner definitions to b=
e deducible. (Deduce T for A&lt;T&gt;::B where template &lt;typename T&gt; =
class A { class B {}; }; =C2=A0(This may have a edge-case with specializati=
ons).<br>or,<div>Type traits struct like coroutines for switch of T? This i=
s a bit more of a stretch, and probably isn&#39;t worth it, but would allow=
 switch(std::variant...) (as would the first one)=C2=A0<br><br><br><div cla=
ss=3D"prettyprint" style=3D"border-width: 1px; border-style: solid; border-=
color: rgb(187, 187, 187); background-color: rgb(250, 250, 250); word-wrap:=
 break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><di=
v class=3D"prettyprint" style=3D"border-width: 1px; border-style: solid; bo=
rder-color: rgb(187, 187, 187); font-family: Arial, Helvetica, sans-serif; =
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpretty=
print"><div class=3D"subprettyprint"><div class=3D"subprettyprint"><span st=
yle=3D"color: rgb(0, 0, 0); font-family: Arial, Helvetica, sans-serif;">// =
Support code for the example at the beginning of the message:<br><br>// Def=
aults to something that isn&#39;t an enum.</span><br></div><div class=3D"su=
bprettyprint"><font color=3D"#000000"><div class=3D"subprettyprint">templat=
e &lt;typename Enum, typename T, typename =3D std::enable_if_t&lt;std::is_e=
num&lt;Enum&gt;::value&gt;&gt;</div><div class=3D"subprettyprint">struct co=
nverted_to_enum {};</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">template &lt;typename T&gt;</div><div class=3D"subprett=
yprint">class TypeEnumHelper {</div><div class=3D"subprettyprint">=C2=A0pub=
lic:</div><div class=3D"subprettyprint">=C2=A0 template &lt;typename Enum, =
Enum =3D converted_to_enum&lt;Enum, T&gt;::value&gt;</div><div class=3D"sub=
prettyprint">=C2=A0 constexpr operator Enum() const {</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 return converted_to_enum&lt;Enum, T&gt;::value;=
</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettypr=
int">};</div><div class=3D"subprettyprint"><br></div><div class=3D"subprett=
yprint">template &lt;typename T&gt;</div><div class=3D"subprettyprint">cons=
texpr TypeEnumHelper&lt;T&gt; type_enum =3D TypeEnumHelper&lt;T&gt;();</div=
><div class=3D"subprettyprint"><br><div class=3D"subprettyprint">#define AS=
SIGN_ENUM_TAG(UnionEnumType, Class, EnumTag) \</div><div class=3D"subpretty=
print">template&lt;&gt; =C2=A0\</div><div class=3D"subprettyprint">struct c=
onverted_to_enum&lt;UnionEnumType, Class&gt; { \</div><div class=3D"subpret=
typrint">=C2=A0 static constexpr UnionEnumType value =3D UnionEnumType:: En=
umTag; \</div><div class=3D"subprettyprint">};</div></div></font></div></di=
v></div></code></div><span style=3D"font-family: Arial, Helvetica, sans-ser=
if; background-color: rgb(255, 255, 255);"></span></div></code></div></div>=
</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/e0683c7a-3db4-4ee6-b10b-649d13c94cd5%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/e0683c7a-3db4-4ee6-b10b-649d13c94cd5=
%40isocpp.org</a>.<br />

------=_Part_10904_784088170.1509551957293--

------=_Part_10903_1031879791.1509551957293--

.


Author: Barry Revzin <barry.revzin@gmail.com>
Date: Wed, 1 Nov 2017 09:37:42 -0700 (PDT)
Raw View
------=_Part_11515_560473485.1509554262996
Content-Type: multipart/alternative;
 boundary="----=_Part_11516_1093647123.1509554262996"

------=_Part_11516_1093647123.1509554262996
Content-Type: text/plain; charset="UTF-8"

You're looking for a language feature called pattern matching.

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.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/388ea94a-6cff-411a-abf4-e8782d207a02%40isocpp.org.

------=_Part_11516_1093647123.1509554262996
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">You&#39;re looking for a language feature called pattern m=
atching.<div><br></div><div>An earlier proposal can be found here:=C2=A0htt=
p://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0095r1.html</div><div=
>My understanding is that David Sankel is working with Michael Park (who wr=
ote a pattern matching library: http://github.com/mpark/patterns) on a new =
draft.=C2=A0</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/388ea94a-6cff-411a-abf4-e8782d207a02%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/388ea94a-6cff-411a-abf4-e8782d207a02=
%40isocpp.org</a>.<br />

------=_Part_11516_1093647123.1509554262996--

------=_Part_11515_560473485.1509554262996--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Wed, 1 Nov 2017 18:46:53 +0200
Raw View
On 1 November 2017 at 18:37, Barry Revzin <barry.revzin@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.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbVgsbTxCahoKLkQVNKGJkiJEC3QS9ugTDVEzY6r6%3D3fw%40mail.gmail.com.

.