Topic: Core Language featuConstructors for


Author: Andrey Semashev <andrey.semashev@gmail.com>
Date: Thu, 6 Oct 2016 12:24:29 +0300
Raw View
On 10/06/16 10:23, Manuel Bergler wrote:
> Am Donnerstag, 6. Oktober 2016 09:11:23 UTC+2 schrieb mihailn...@gmail.com:
>
>     bitset does not support named flags and I doubt it is designed to be
>     used to store non-mutually exclusive options. It is a container for
>     bits. It has its uses.
>     As for mixing and enum + bitset - this is even more clunky then a
>     struct wrapper or macro do define the operators (Qt way).
>
>
> For mutually exclusive flags I agree, enums are the way to go. But as I
> understood it he wanted `operator|` and `operator&` so that you can use
> enums as
> non-exclusive flags. And this you can easily get with `std::bitset` and
> and enum as an index into the bitset:
>
> |
> enum class Features : size_t {
>     ColoredText,
>     ColoredBorder,
>     Scrollbar
> }
>
> std::bitset<3> features;
> features.set(Feature::ColoredText);
> features.set(Feature::Scrollbar);
> |

The problem with bitset is that it is a distinct type from the enum and
nothing suggests their connection. You could use a different enum to
index bits in the bitset by mistake and never notice.

Another problem is that enum classes don't allow implicit conversions to
integers, so your code above doesn't work. You have to do this instead:

   features.set(static_cast< size_t >(Feature::ColoredText));
   features.set(static_cast< size_t >(Feature::Scrollbar));

This is just cumbersome and ugly. Granted, you'd have to do similar
casts when you use scoped enums as bit values anyway, so currently they
are a poor choice for bit fields anyway.

--
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/edad843d-b607-1e99-a6b1-6f61ea25eb42%40gmail.com.

.


Author: Manuel Bergler <berglerma@gmail.com>
Date: Thu, 6 Oct 2016 03:38:35 -0700 (PDT)
Raw View
------=_Part_248_1274342051.1475750315649
Content-Type: multipart/alternative;
 boundary="----=_Part_249_1332919120.1475750315650"

------=_Part_249_1332919120.1475750315650
Content-Type: text/plain; charset=UTF-8



Am Donnerstag, 6. Oktober 2016 11:24:33 UTC+2 schrieb Andrey Semashev:
>
> On 10/06/16 10:23, Manuel Bergler wrote:
> > Am Donnerstag, 6. Oktober 2016 09:11:23 UTC+2 schrieb
> mihailn...@gmail.com:
> >
> >     bitset does not support named flags and I doubt it is designed to be
> >     used to store non-mutually exclusive options. It is a container for
> >     bits. It has its uses.
> >     As for mixing and enum + bitset - this is even more clunky then a
> >     struct wrapper or macro do define the operators (Qt way).
> >
> >
> > For mutually exclusive flags I agree, enums are the way to go. But as I
> > understood it he wanted `operator|` and `operator&` so that you can use
> > enums as
> > non-exclusive flags. And this you can easily get with `std::bitset` and
> > and enum as an index into the bitset:
> >
> > |
> > enum class Features : size_t {
> >     ColoredText,
> >     ColoredBorder,
> >     Scrollbar
> > }
> >
> > std::bitset<3> features;
> > features.set(Feature::ColoredText);
> > features.set(Feature::Scrollbar);
> > |
>
> The problem with bitset is that it is a distinct type from the enum and
> nothing suggests their connection. You could use a different enum to
> index bits in the bitset by mistake and never notice.
>

I didn't originally intend to go into too much details as I don't feel it is
relevant to the discussion whether or not constructors for enums are
a good idea. Of course you can always imagine even more features.

Typically I'd package them into a single class and just forward `.set`,
`.reset`, `test` and `to_ulong` the bitset, then you clearly have a
connection
between the two.

class WindowFeatures {
public:
    enum Feature : size_t {
        ColoredText,
        ColoredBorder,
        Scrollbar,
        NumberOfFeatures
    };

    unsigned long to_ulong() const {
        return _bitset.to_ulong();
    }

   void set(Feature f) {
       _bitset.set(f);
   }

   void reset(Feature f) {
       _bitset.reset(f);
   }

   bool test(Feature f) const {
       return _bitset.test();
   }

private:
   std::bitset<NumberOfFeatures> _bitset;
};

auto features = WindowFeatures{};
features.set(WindowFeatures::ColoredText);
features.set(WindowFeatures::Scrollbar);

I find this much more readable than the C-style bitwise `or`, in particular
testing
if a flag is set via bitwise `and` just looks weird and doesn't at all
convey intend.

If you like you can even add a forwarding constructor so that if you load a
saved
bitset from e.g. a config file you can check validity there. And it doesn't
add any
boilerplate at the call site compared to the bitset version in my previous
reply,
to the contrary it even is easier to use since you don't need to know the
number
of flags there are.

Admittedly it is a little more verbose compared to C style non-exclusive
flags,
but also less error prone (ever defined the enumerator wrong, e.g. as 0x3
instead
of 0x4 due to a typo?), and you need an additional call to `to_ulong` when
interfacing with C code. But I'll take that any day, since it even is more
typesafe,
and for all intends and purposes that enum is never used for things other
than
calling `set`, `reset` and `test`.

Of course it would be nice if this could be generalized with a template
using
some means of inspection, but at least the boilerplate only has to be
written once,
so this is not the issue I wanted to address with constructors for enums.

My main concern is when you use enums for exclusive flags, i.e. when you at
some point need to use a `switch` over the values, which will be in most
cases
also at more than one point in you codebase.

There you can also package them into a class

class Color {
public:
    enum Colors : uint8_t {
       red,
       yellow,
       green
    };

    Color(int i) {
       // switch as before
    }

    Colors get() const {
        return _color;
    }

    // assignment from Color::Colors and Color,
    // (non-)equality and explicit conversion to uint8_t
    // operators

private:
    Colors _color;
};

but then in every `switch` and every interface to C code you need to add the
call to `.get()`, so you end up with boilerplate at every call site. The
overhead
to write the class also is way larger than the overhead for the bitset one,
I omitted all the operators for a reason.

Unfortunately, in my experience, exclusive flags are much more common
than bitsets, so this adds a massive overhead. In particular in those cases
when you would normally just use a nested enum, you now get an enum
nested inside a nested class.

So what ends up happening is that people resort to plain enums and
`static_cast` instead since it is much more convenient and then they
add a `default` case to all switches over values of that enumeration,
supposedly to catch the cases in which the casted integral value was
not one of the enumerators. At first glance this appears to do the right
thing, but if the enum wasn't declared with a fixed underlying type
you quickly end up with undefined behavior.

Hence my proposal for constructors for enums. If the right thing is more
convenient than the dangerous thing we'll ultimately end up with more
robust code.

>
> Another problem is that enum classes don't allow implicit conversions to
> integers, so your code above doesn't work. You have to do this instead:
>
>    features.set(static_cast< size_t >(Feature::ColoredText));
>    features.set(static_cast< size_t >(Feature::Scrollbar));
>
> This is just cumbersome and ugly. Granted, you'd have to do similar
> casts when you use scoped enums as bit values anyway, so currently they
> are a poor choice for bit fields anyway.
>

Yeah, I accidentally put the `class` there.

--
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/d29feefb-7e2b-4449-8337-89b1b65968c7%40isocpp.org.

------=_Part_249_1332919120.1475750315650
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>Am Donnerstag, 6. Oktober 2016 11:24:33 UTC+2 schr=
ieb Andrey Semashev:<blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 10/06/1=
6 10:23, Manuel Bergler wrote:
<br>&gt; Am Donnerstag, 6. Oktober 2016 09:11:23 UTC+2 schrieb <a>mihailn..=
..@gmail.com</a>:
<br>&gt;
<br>&gt; =C2=A0 =C2=A0 bitset does not support named flags and I doubt it i=
s designed to be
<br>&gt; =C2=A0 =C2=A0 used to store non-mutually exclusive options. It is =
a container for
<br>&gt; =C2=A0 =C2=A0 bits. It has its uses.
<br>&gt; =C2=A0 =C2=A0 As for mixing and enum + bitset - this is even more =
clunky then a
<br>&gt; =C2=A0 =C2=A0 struct wrapper or macro do define the operators (Qt =
way).
<br>&gt;
<br>&gt;
<br>&gt; For mutually exclusive flags I agree, enums are the way to go. But=
 as I
<br>&gt; understood it he wanted `operator|` and `operator&amp;` so that yo=
u can use
<br>&gt; enums as
<br>&gt; non-exclusive flags. And this you can easily get with `std::bitset=
` and
<br>&gt; and enum as an index into the bitset:
<br>&gt;
<br>&gt; |
<br>&gt; enum class Features : size_t {
<br>&gt; =C2=A0 =C2=A0 ColoredText,
<br>&gt; =C2=A0 =C2=A0 ColoredBorder,
<br>&gt; =C2=A0 =C2=A0 Scrollbar
<br>&gt; }
<br>&gt;
<br>&gt; std::bitset&lt;3&gt; features;
<br>&gt; features.set(Feature::<wbr>ColoredText);
<br>&gt; features.set(Feature::<wbr>Scrollbar);
<br>&gt; |
<br>
<br>The problem with bitset is that it is a distinct type from the enum and=
=20
<br>nothing suggests their connection. You could use a different enum to=20
<br>index bits in the bitset by mistake and never notice.
<br></blockquote><div><br>I didn&#39;t originally intend to go into too muc=
h details as I don&#39;t feel it is<br>relevant to the discussion whether o=
r not constructors for enums are<br>a good idea. Of course you can always i=
magine even more features.<br><br>Typically I&#39;d package them into a sin=
gle class and just forward `.set`,<br>`.reset`, `test` and `to_ulong` the b=
itset, then you clearly have a connection<br>between the two.<br><br><div s=
tyle=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 1=
87); border-style: solid; border-width: 1px; overflow-wrap: break-word;" cl=
ass=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettyprin=
t"><span style=3D"color: #008;" class=3D"styled-by-prettify">class</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">WindowFeatures</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">public</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">enum</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">Feature</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> size_t </sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 </span><span style=3D"color: #606;" class=3D"styled-by-prettify"=
>ColoredText</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">ColoredBorder</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #606;=
" class=3D"styled-by-prettify">Scrollbar</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"=
color: #606;" class=3D"styled-by-prettify">NumberOfFeatures</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=C2=A0 =C2=A0 </sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">unsigned</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">long</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> to_ulong</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">const</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> _bitset</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">to_ulong</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br>=C2=A0 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>=C2=A0<br>=C2=A0 =C2=A0</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">set</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #606;" class=3D"styled-by-prettify">Feature</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> f</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0_bitset</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"=
color: #008;" class=3D"styled-by-prettify">set</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">f</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>=C2=A0 =C2=A0</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br><br>=C2=A0 =C2=A0</span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> reset</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #606;" class=3D"styled-by-prettify">=
Feature</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> f<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0_bitse=
t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">reset</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">f</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>=C2=A0 =C2=A0</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br>=C2=A0 =C2=A0</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">bool</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> test</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Feature</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> f</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">return</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> _bitset</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">test</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">private</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>=C2=A0 =C2=A0std</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">bitset</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">NumberOfFeatures</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> _bitset</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> features </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #60=
6;" class=3D"styled-by-prettify">WindowFeatures</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">{};</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"><br>features</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">.</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">set</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">(</span><span style=3D"color: #606;" class=3D"styled-by-pr=
ettify">WindowFeatures</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">::</span><span style=3D"color: #606;" class=3D"styled-by-pretti=
fy">ColoredText</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
>features</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">set</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #606;" class=3D"styled-by-prettify">WindowFeatures</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Scrollbar</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>I =
find this much more readable than the C-style bitwise `or`, in particular t=
esting<br>if a flag is set via bitwise `and` just looks weird and doesn&#39=
;t at all convey intend.<br><br>If you like you can even add a forwarding c=
onstructor so that if you load a saved<br>bitset from e.g. a config file yo=
u can check validity there. And it doesn&#39;t add any <br>boilerplate at t=
he call site compared to the bitset version in my previous reply,<br>to the=
 contrary it even is easier to use since you don&#39;t need to know the num=
ber<br>of flags there are. <br><br>Admittedly it is a little more verbose c=
ompared to C style non-exclusive flags, <br>but also less error prone (ever=
 defined the enumerator wrong, e.g. as 0x3 instead<br>of 0x4 due to a typo?=
), and you need an additional call to `to_ulong` when<br>interfacing with C=
 code. But I&#39;ll take that any day, since it even is more typesafe,<br>a=
nd for all intends and purposes that enum is never used for things other th=
an<br>calling `set`, `reset` and `test`.<br><br>Of course it would be nice =
if this could be generalized with a template using<br>some means of inspect=
ion, but at least the boilerplate only has to be written once,<br>so this i=
s not the issue I wanted to address with constructors for enums.<br><br>My =
main concern is when you use enums for exclusive flags, i.e. when you at<br=
>some point need to use a `switch` over the values, which will be in most c=
ases<br>also at more than one point in you codebase.<br><br>There you can a=
lso package them into a class<br>=C2=A0<div style=3D"background-color: rgb(=
250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bord=
er-width: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;=
" class=3D"styled-by-prettify">class</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"sty=
led-by-prettify">Color</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">public</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">enum</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"=
color: #606;" class=3D"styled-by-prettify">Colors</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> uint8_t </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0red</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0yellow</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
green<br>=C2=A0 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br><br>=C2=A0 =C2=A0 </span><span style=3D"color: #606;" class=3D"sty=
led-by-prettify">Color</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> i</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0</span=
><span style=3D"color: #800;" class=3D"styled-by-prettify">// switch as bef=
ore</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=
=C2=A0 =C2=A0 </span><span style=3D"color: #606;" class=3D"styled-by-pretti=
fy">Colors</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">get</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">return</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> _color</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 <br>=C2=A0 =C2=A0 </span><span st=
yle=3D"color: #800;" class=3D"styled-by-prettify">// assignment from Color:=
:Colors and Color,</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #800;" class=3D"styl=
ed-by-prettify">// (non-)equality and explicit conversion to uint8_t</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0=
 </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// operat=
ors</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br=
></span><span style=3D"color: #008;" class=3D"styled-by-prettify">private</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </s=
pan><span style=3D"color: #606;" class=3D"styled-by-prettify">Colors</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> _color</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span></div></code></div><br>but then=
 in every `switch` and every interface to C code you need to add the<br>cal=
l to `.get()`, so you end up with boilerplate at every call site. The overh=
ead<br>to write the class also is way larger than the overhead for the bits=
et one,<br>I omitted all the operators for a reason.<br><br>Unfortunately, =
in my experience, exclusive flags are much more common<br>than bitsets, so =
this adds a massive overhead. In particular in those cases<br>when you woul=
d normally just use a nested enum, you now get an enum<br>nested inside a n=
ested class.<br><br>So what ends up happening is that people resort to plai=
n enums and<br>`static_cast` instead since it is much more convenient and t=
hen they<br>add a `default` case to all switches over values of that enumer=
ation,<br>supposedly to catch the cases in which the casted integral value =
was<br>not one of the enumerators. At first glance this appears to do the r=
ight<br>thing, but if the enum wasn&#39;t declared with a fixed underlying =
type<br>you quickly end up with undefined behavior.<br>=C2=A0<br>Hence my p=
roposal for constructors for enums. If the right thing is more<br>convenien=
t than the dangerous thing we&#39;ll ultimately end up with more <br>robust=
 code.<br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>Another problem is that enum classes don&#39;t allow implicit conversio=
ns to=20
<br>integers, so your code above doesn&#39;t work. You have to do this inst=
ead:
<br>
<br>=C2=A0 =C2=A0features.set(static_cast&lt; size_t &gt;(Feature::ColoredT=
ext));
<br>=C2=A0 =C2=A0features.set(static_cast&lt; size_t &gt;(Feature::Scrollba=
r));
<br>
<br>This is just cumbersome and ugly. Granted, you&#39;d have to do similar=
=20
<br>casts when you use scoped enums as bit values anyway, so currently they=
=20
<br>are a poor choice for bit fields anyway.
<br></blockquote><div><br>Yeah, I accidentally put the `class` there.<br><b=
r></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/d29feefb-7e2b-4449-8337-89b1b65968c7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d29feefb-7e2b-4449-8337-89b1b65968c7=
%40isocpp.org</a>.<br />

------=_Part_249_1332919120.1475750315650--

------=_Part_248_1274342051.1475750315649--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Fri, 07 Oct 2016 08:48:09 +0200
Raw View
Em quinta-feira, 6 de outubro de 2016, =C3=A0s 08:13:54 CEST, Ivan Kush esc=
reveu:
> int j =3D 5;
> FooEnum enum =3D static_cast<FooEnum>(j);//OK
> int i =3D 6;
> FooEnum enum =3D static_cast<FooEnum>(i);//throw exception

static casts don't throw exceptions. Either they succeed at compile time, o=
r=20
they are ill-formed at compile time.

Note that the static_cast can call a constructor or a conversion operator,=
=20
which in turn can throw. But that's not the same as the static_cast throwin=
g.=20
That brings us back to the original proposal: add a conversion function.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
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 e=
mail 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/1996377.s3CEpErBo8%40tjmaciei-mobl1.

.