220 30455 <57258435-5d82-48e7-8ed7-3c38682418fb@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: gmisocpp@gmail.com
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: enum_cast proposal
Date: Tue, 10 Jan 2017 04:48:59 -0800 (PST)
Lines: 368
Approved: news@gmane.org
Message-ID: <57258435-5d82-48e7-8ed7-3c38682418fb@isocpp.org>
References: <efdf2357-00a6-408a-8772-12f99135a880@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_2523_1149900171.1484052539792"
X-Trace: blaine.gmane.org 1484052551 16442 195.159.176.226 (10 Jan 2017 12:49:11 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Tue, 10 Jan 2017 12:49:11 +0000 (UTC)
Cc: m.cencora@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCM3TRNUXUDBBPNQ2PBQKGQEACN3WMQ@isocpp.org Tue Jan 10 13:49:05 2017
Return-path: <std-proposals+bncBCM3TRNUXUDBBPNQ2PBQKGQEACN3WMQ@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-yb0-f199.google.com ([209.85.213.199])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCM3TRNUXUDBBPNQ2PBQKGQEACN3WMQ@isocpp.org>)
	id 1cQvrF-0002eD-Lo
	for gclcip-std-proposals@m.gmane.org; Tue, 10 Jan 2017 13:48:57 +0100
Original-Received: by mail-yb0-f199.google.com with SMTP id 186sf561135725yby.5
        for <gclcip-std-proposals@m.gmane.org>; Tue, 10 Jan 2017 04:49:02 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=qHzP+OIgcra2BWFKfAURf8fq8FiWWVWWPu+VNpG6SMQ=;
        b=I68b0aIiObPv7SpIFMU+ihEg1KvAlOOBn2uTrbOrPgXnnrGRtIyH8iR9w6G11fv2N3
         LPc5yTARRmLXwGYS8GeNlv+UNz+uuTCJSXGWnmZGTSPxJ++FOt6CcT7SGHpbO3DlDBT8
         65qGwU3o06koxzYDx/enTez/Pzb0RdzVKb986o8IteSg45WxfPqfcxwE9bgg4MuAvc2c
         h3Dsb9xOE98+TzQZ/yPYXSYbI0W1qoR2PrQiA+qnLMrk6YwHbypFroMKbUU97gGwX+SC
         rVgHLGefgjE0DZ3rYslpy1vB0fxph7bOAvzVrHTVGm9q+npD7o/BKXoNqUrhZo7cCIUE
         0R1Q==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=qHzP+OIgcra2BWFKfAURf8fq8FiWWVWWPu+VNpG6SMQ=;
        b=UFjUs3LNEkvfPVLP6k1O3LaGaWZeZJat4QeN/DbhIpZFYuEiS4woBs61mzOQwKCb8w
         /2T1d5RRQVFaVDshm1O0YAlCIhOSL+B8iV3bjEMXUQFKuIVdoiM/bfXF365sjspFUZPK
         ouCo0qua32cwIm/3PyiQEKoWjQDHclxjRIOkmIaivD9LB6SIjByF9RJ57WCxzaXmHE7F
         Whg4jkAU44FtQYvhWCX0NU5jbfkRgdUnBOMZBPfQUJexCLiNdvbYJcIXPCMnx0YFtD1q
         +8DAHHlv6ED2WIAbZJtrF19M4dCKf9dze1L8VTyjc7yT617KHr+zCeumGV7jGHO9rhIu
         AgRA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:cc:message-id:in-reply-to
         :references:subject:mime-version:x-original-sender:reply-to
         :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post
         :list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=qHzP+OIgcra2BWFKfAURf8fq8FiWWVWWPu+VNpG6SMQ=;
        b=F7wxT2yP1K7cEraDLtP0IRlg7J+eKsgpV7YRtfhyPGppiGJYcrqn0B5BczU/zVb/BE
         O2830Qk0FMssRNP38F6aB1IfYMCi/3mg9igYxg9Z2VkMJlEkULa5CiIlgIEvFfePNCq8
         AUgsmVCPCoT9Pwo5HZahORx9Kv6rzy0/QXuYt8YkpYVtl15r6e3Qa0Qj2774xoenr9N0
         qE2fP0ezklI8Px3bQqtKBN7LnyuROs1D3wIMnnm+WFBB+i6lYnkapB7E10dUKNilQxHZ
         hj0wee3N9HpGyLzOe3+PRK/LPUp1TTh5aV1PTRVK7Y6RT759UQ99wIpnXtRT+OSbzHl9
         6mDg==
X-Gm-Message-State: AIkVDXLGregCXOA7+ZuDEA8ejNbVTdERl13KhG7V8fuMz/1QKA7L+7Wsl6jKM2iF7h0ECw==
X-Received: by 10.13.196.133 with SMTP id g127mr897317ywd.153.1484052541853;
        Tue, 10 Jan 2017 04:49:01 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.18.211 with SMTP id g77ls1249612otg.39.gmail; Tue, 10 Jan
 2017 04:49:01 -0800 (PST)
X-Received: by 10.157.8.10 with SMTP id 10mr106744oty.19.1484052541064;
        Tue, 10 Jan 2017 04:49:01 -0800 (PST)
In-Reply-To: <efdf2357-00a6-408a-8772-12f99135a880@isocpp.org>
X-Original-Sender: gmisocpp@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:30455
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/30455>

------=_Part_2523_1149900171.1484052539792
Content-Type: multipart/alternative; 
	boundary="----=_Part_2524_1908813640.1484052539793"

------=_Part_2524_1908813640.1484052539793
Content-Type: text/plain; charset=UTF-8



On Tuesday, January 3, 2017 at 10:56:05 PM UTC+13, m.ce...@gmail.com wrote:
>
> Hi,
>
> I propose to add a enum_cast function that safely casts int value to a 
> target enum type if int value represents a valid enumerator.
>
> template <typename Enum, typename Int>
> optional<Enum> enum_cast(Int value);
>
> requires: is_enum<Enum>, is_integral<Int>
>
> enum color
> {
>    red = 1,
>    green = 200,
>    blue = 3
> };
>
> static_assert(enum_cast<color>(200u) == color::green);
> static_assert(enum_cast<color>(3) == color::blue);
> static_assert(enum_cast<color>(4) == nullopt);
>
>
> This should work for both scoped and unscoped enums.
> For opaque enums this would only check if value fits in underlying type.
>
> Why do we want this:
>  - validation of input data (e.g. coming from user or deserialization).
>  - other?
>
> I know this could be purely library extension if based on reflection, but 
> since we don't know when we will get reflection,
> and implementation based on reflection may not be optimal,
> I think it should be implemented with compiler support (i.e. via 
> __builtin_* intrinsic).
>
> Regards,
> Maciej
>


I was thinking some more about this proposal. I really think the 
functionality you suggest is a good idea.
I hope you proceed with a proposal. If you decide not to let me know.

I hope this post assists you with your proposal. My suggestions are for 
your proposal to look something like this:

In <utility> I think add:

bool template<typename E, typename V> is_enum( V ev )
{
 // compiler magic:
 // Calling this routine causes the compiler to generate or a call a routine
 // that returns true if the value ev matches one of the enum E's
 // values. otherwise false.
}

// Users call this routine to convert an integer to an enum.
They call this if they aren't sure about their conversion data
// and don't mind exceptions and want simple like std::to_string
// They might expect such a function to be present.
// Though to be fair I'm not sure we should encourage this?
// They should get good error messages.
template<typename E, typename V> E to_enum_or_throw(V ev)
{
 if (is_enum<E>(ev))
  return static_cast<E>(ev);
 throw make_bad_enum<E,V>(ev); 
}

template<typename E> class to_enum_result
{
public:
 E enum_value;
 bool is_valid;
};

// Call this if you can't use/afford exceptions. It seems optimal?
template<typename E, typename V> to_enum_result<E> to_enum( V ev ) noexcept
{
  if (is_enum<E, V>(ev))
    return to_enum_result<E>{true,static_cast<E>(ev)};
  return to_enum_result<E>{false, E{}};
}

// if is_valid returns false after to_enum, the user can use these routines 
to get good error
// messages / report how they wish when they wish:

// Some type that holds the largest enum value ever possible.
using std::any_enum_value = unspecified;

class bad_enum
{
public:
   std::any_any_enum_value bad_enum_value;
   std::string enum_type_name;
};
 
template<typename E, typename V> std::bad_enum make_bad_enum(V ev)
{
 // Use some compiler magic to get the name of the name of the enum type E.
 // Use it to construct a message like:
 // '{ev}' is not a legal value for an enum of type '{E}'
 return std::range_error(msg);
}


Note in all methods:
* constrain E to only be an enum or enum class type.
* constrain V to only accept integral types.

Observations
------------

* is_enum() is there for people who just need to check validity and no more.
and saves the user writing redudant boiler plate code that the compiler 
does better.
* to_enum_or_throw() is there for people who find simple works for them.
its name makes it clear that exceptions can happen.
* to_enum() is there for people who need performance and without exceptions.
* We don't depend on optional.
* Means <utility> isn't dependent on optional if we put it there.
* make_bad_enum avoids making bad_enum a template.
* make_bad_enum gives us good error messages and better than 
bad_optional_access.
* make_bad_enum means we can create an error class for reporting elsewhere 
- we don't have to throw it.
* make_bad_enum means we don't expose any get enum_type_name function the 
reflection people will reproduce.
* make_bad_enum gives people flexibility to throw when they are ready 
instead of forcing a throw as soon as conversion fails.
* Might play well with structured bindings.

Main choices:
* We could model this on optional i.e. include has_value etc. but it seems 
simpler not to. Either way is fine to me.
I'm not sure such safety is warranted and from_chars/to_chars is pretty 
simple too so I went that way.
* The caller has all the utilities here to build that or work with optional 
directly - whatever they need.
* I think being able to get good error messages on failure is important.
This tries to enable making decent errors available no matter what method 
or is used.
 i.e. include the enum type name and bad value in the error.
* I've used std::range_error as the exception type for failure but another 
may be appropriate.
bad_enum as an exception type contains the value that was bad and the type 
name that it failed to convert to.
This would allow people to extract the values to construct their own error 
messages (perhaps in other languages like French etc.).

If std::bad_enum is too much API, that could be dropped for just 
std::range_error or something as long a it contains
a full description of the error I think that's fine.

I'd like to know what you and the Committee's disposition towards these 
ideas and views. Hope this helps.

Thanks
GM

-- 
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/57258435-5d82-48e7-8ed7-3c38682418fb%40isocpp.org.

------=_Part_2524_1908813640.1484052539793
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, January 3, 2017 at 10:56:05 PM UTC+13,=
 m.ce...@gmail.com wrote:<blockquote class=3D"gmail_quote" style=3D"margin:=
 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204=
); border-left-width: 1px; border-left-style: solid;"><div dir=3D"ltr">Hi,<=
div><br></div><div>I propose to add a enum_cast function that safely casts =
int value to a target enum type if int value represents a valid enumerator.=
</div><div><br></div><div style=3D"border: 1px solid rgb(187, 187, 187); bo=
rder-image: none; -ms-word-wrap: break-word; background-color: rgb(250, 250=
, 250);"><code><div><span style=3D"color: rgb(0, 0, 136);">template</span><=
span style=3D"color: rgb(0, 0, 0);"> </span><span style=3D"color: rgb(102, =
102, 0);">&lt;</span><span style=3D"color: rgb(0, 0, 136);">typename</span>=
<span style=3D"color: rgb(0, 0, 0);"> </span><span style=3D"color: rgb(102,=
 0, 102);">Enum</span><span style=3D"color: rgb(102, 102, 0);">,</span><spa=
n style=3D"color: rgb(0, 0, 0);"> </span><span style=3D"color: rgb(0, 0, 13=
6);">typename</span><span style=3D"color: rgb(0, 0, 0);"> </span><span styl=
e=3D"color: rgb(102, 0, 102);">Int</span><span style=3D"color: rgb(102, 102=
, 0);">&gt;</span><span style=3D"color: rgb(0, 0, 0);"><br>optional</span><=
span style=3D"color: rgb(102, 102, 0);">&lt;</span><span style=3D"color: rg=
b(102, 0, 102);">Enum</span><span style=3D"color: rgb(102, 102, 0);">&gt;</=
span><span style=3D"color: rgb(0, 0, 0);"> enum_cast</span><span style=3D"c=
olor: rgb(102, 102, 0);">(</span><span style=3D"color: rgb(102, 0, 102);">I=
nt</span><span style=3D"color: rgb(0, 0, 0);"> value</span><span style=3D"c=
olor: rgb(102, 102, 0);">);</span><span style=3D"color: rgb(0, 0, 0);"><br>=
<br>requires</span><span style=3D"color: rgb(102, 102, 0);">:</span><span s=
tyle=3D"color: rgb(0, 0, 0);"> is_enum</span><span style=3D"color: rgb(102,=
 102, 0);">&lt;</span><font color=3D"#000000"><span style=3D"color: rgb(102=
, 0, 102);">Enum</span></font><span style=3D"color: rgb(102, 102, 0);">&gt;=
,</span><span style=3D"color: rgb(0, 0, 0);"> is_integral</span><span style=
=3D"color: rgb(102, 102, 0);">&lt;</span><span style=3D"color: rgb(102, 0, =
102);">Int</span><span style=3D"color: rgb(102, 102, 0);">&gt;</span><span =
style=3D"color: rgb(0, 0, 0);"><br><br></span><span style=3D"color: rgb(0, =
0, 136);">enum</span><span style=3D"color: rgb(0, 0, 0);"> color<br></span>=
<span style=3D"color: rgb(102, 102, 0);">{</span><span style=3D"color: rgb(=
0, 0, 0);"><br>=C2=A0 =C2=A0red </span><span style=3D"color: rgb(102, 102, =
0);">=3D</span><span style=3D"color: rgb(0, 0, 0);"> </span><span style=3D"=
color: rgb(0, 102, 102);">1</span><span style=3D"color: rgb(102, 102, 0);">=
,</span><span style=3D"color: rgb(0, 0, 0);"><br>=C2=A0 =C2=A0green </span>=
<span style=3D"color: rgb(102, 102, 0);">=3D</span><span style=3D"color: rg=
b(0, 0, 0);"> </span><span style=3D"color: rgb(0, 102, 102);">200</span><sp=
an style=3D"color: rgb(102, 102, 0);">,</span><span style=3D"color: rgb(0, =
0, 0);"><br>=C2=A0 =C2=A0blue </span><span style=3D"color: rgb(102, 102, 0)=
;">=3D</span><span style=3D"color: rgb(0, 0, 0);"> </span><span style=3D"co=
lor: rgb(0, 102, 102);">3</span><span style=3D"color: rgb(0, 0, 0);"><br></=
span><span style=3D"color: rgb(102, 102, 0);">};</span><span style=3D"color=
: rgb(0, 0, 0);"><br><br></span><span style=3D"color: rgb(0, 0, 136);">stat=
ic_assert</span><span style=3D"color: rgb(102, 102, 0);">(</span><span styl=
e=3D"color: rgb(0, 0, 0);">enum_cast</span><span style=3D"color: rgb(0, 136=
, 0);">&lt;color&gt;</span><span style=3D"color: rgb(102, 102, 0);"><wbr>(<=
/span><font color=3D"#006666"><span style=3D"color: rgb(0, 102, 102);">200u=
</span></font><span style=3D"color: rgb(102, 102, 0);">)</span><span style=
=3D"color: rgb(0, 0, 0);"> </span><span style=3D"color: rgb(102, 102, 0);">=
=3D=3D</span><span style=3D"color: rgb(0, 0, 0);"> color</span><span style=
=3D"color: rgb(102, 102, 0);">::</span><font color=3D"#000000"><span style=
=3D"color: rgb(0, 0, 0);">green</span></font><span style=3D"color: rgb(102,=
 102, 0);">);</span><span style=3D"color: rgb(0, 0, 0);"><br></span><span s=
tyle=3D"color: rgb(0, 0, 136);">static_assert</span><span style=3D"color: r=
gb(102, 102, 0);">(</span><span style=3D"color: rgb(0, 0, 0);">enum_cast</s=
pan><span style=3D"color: rgb(0, 136, 0);">&lt;color&gt;</span><span style=
=3D"color: rgb(102, 102, 0);"><wbr>(</span><span style=3D"color: rgb(0, 102=
, 102);">3</span><span style=3D"color: rgb(102, 102, 0);">)</span><span sty=
le=3D"color: rgb(0, 0, 0);"> </span><span style=3D"color: rgb(102, 102, 0);=
">=3D=3D</span><span style=3D"color: rgb(0, 0, 0);"> color</span><span styl=
e=3D"color: rgb(102, 102, 0);">::</span><span style=3D"color: rgb(0, 0, 0);=
">blue</span><span style=3D"color: rgb(102, 102, 0);">);</span><span style=
=3D"color: rgb(0, 0, 0);"><br></span><span style=3D"color: rgb(0, 0, 136);"=
>static_assert</span><span style=3D"color: rgb(102, 102, 0);">(</span><span=
 style=3D"color: rgb(0, 0, 0);">enum_cast</span><span style=3D"color: rgb(0=
, 136, 0);">&lt;color&gt;</span><span style=3D"color: rgb(102, 102, 0);"><w=
br>(</span><span style=3D"color: rgb(0, 102, 102);">4</span><span style=3D"=
color: rgb(102, 102, 0);">)</span><span style=3D"color: rgb(0, 0, 0);"> </s=
pan><span style=3D"color: rgb(102, 102, 0);">=3D=3D</span><span style=3D"co=
lor: rgb(0, 0, 0);"> nullopt</span><span style=3D"color: rgb(102, 102, 0);"=
>);</span><span style=3D"color: rgb(0, 0, 0);"><br><br></span></div></code>=
</div><div><br></div><div>This should work for both scoped and unscoped enu=
ms.</div><div>For opaque enums this would only check if value fits in under=
lying type.<br></div><div><br></div><div>Why do we want this:<br></div><div=
>=C2=A0- validation of input data (e.g. coming from user or deserialization=
).</div><div>=C2=A0- other?</div><div><br></div><div>I know this could be p=
urely library extension if based on reflection, but since we don&#39;t know=
 when we will get reflection,</div><div>and implementation based on reflect=
ion may not be optimal,</div><div>I think it should be implemented with com=
piler support (i.e. via __builtin_* intrinsic).</div><div><br></div><div>Re=
gards,</div><div>Maciej</div></div></blockquote><div><br></div><div><br></d=
iv><div>I was thinking some more about this proposal. I really think the fu=
nctionality you suggest=C2=A0is a good idea.</div><div>I hope you proceed w=
ith a proposal.=C2=A0If you decide not to let me know.</div><div><br></div>=
<div>I hope this post assists you with your proposal.=C2=A0My suggestions a=
re for your proposal to look something like this:</div><div><br></div><div>=
In &lt;utility&gt; I think add:</div><div><br></div><div>bool template&lt;t=
ypename E, typename V&gt; is_enum( V ev )</div><div>{</div><div>=C2=A0// co=
mpiler=C2=A0magic:</div><div>=C2=A0// Calling this routine causes the compi=
ler to generate or a call a routine</div><div>=C2=A0// that returns true if=
 the value ev matches one of the enum E&#39;s</div><div>=C2=A0// values. ot=
herwise false.</div><div>}</div><div><br></div><div>// Users call this rout=
ine to convert an integer to an enum.</div><div>They call this if they=C2=
=A0aren&#39;t sure about=C2=A0their conversion data</div><div>// and don&#3=
9;t mind exceptions and want simple like std::to_string</div><div>// They m=
ight expect such a function to be present.</div><div>// Though to be fair I=
&#39;m not sure we should encourage this?</div><div>//=C2=A0They should get=
 good error messages.</div><div>template&lt;typename E, typename V&gt; E to=
_enum_or_throw(V ev)</div><div>{</div><div>=C2=A0if (is_enum&lt;E&gt;(ev))<=
/div><div>=C2=A0=C2=A0return static_cast&lt;E&gt;(ev);</div><div>=C2=A0thro=
w make_bad_enum&lt;E,V&gt;(ev);=C2=A0</div><div>}</div><div><br></div><div>=
<div>template&lt;typename E&gt; class to_enum_result</div><div>{</div><div>=
public:</div><div>=C2=A0E enum_value;</div><div>=C2=A0bool is_valid;</div><=
div>};</div><div><br></div></div><div>// Call this if you can&#39;t use/aff=
ord exceptions. It seems optimal?</div><div>template&lt;typename E, typenam=
e V&gt; to_enum_result&lt;E&gt; to_enum( V ev ) noexcept</div><div>{</div><=
div>=C2=A0 if (is_enum&lt;E, V&gt;(ev))</div><div>=C2=A0=C2=A0=C2=A0 return=
 to_enum_result&lt;E&gt;{true,static_cast&lt;E&gt;(ev)};</div><div>=C2=A0 r=
eturn to_enum_result&lt;E&gt;{false, E{}};</div><div>}</div><div><br></div>=
<div>// if is_valid=C2=A0returns false after to_enum, the user can use thes=
e routines to get good error</div><div>// messages / report how they wish w=
hen they wish:</div><div><br></div><div><div><div>// Some type that holds t=
he largest enum value ever possible.</div><div><div>using std::any_enum_val=
ue =3D unspecified;</div><div><br></div></div></div><div>class bad_enum</di=
v><div>{</div><div>public:</div><div>=C2=A0=C2=A0=C2=A0std::any_any_enum_va=
lue bad_enum_value;</div><div>=C2=A0=C2=A0 std::string enum_type_name;<br>}=
;</div><div>=C2=A0</div>template&lt;typename E, typename V&gt; std::bad_enu=
m make_bad_enum(V ev)</div><div>{</div><div>=C2=A0// Use some compiler magi=
c to get the name of the name of the=C2=A0enum type=C2=A0E.</div><div>=C2=
=A0// Use it to construct a message like:</div><div>=C2=A0// &#39;{ev}&#39;=
 is not a legal value for an enum of type &#39;{E}&#39;</div><div>=C2=A0ret=
urn std::range_error(msg);</div><div>}</div><div><br></div><div><br></div><=
div><div>Note in all methods:</div><div>* constrain E to only be an enum or=
 enum class type.</div><div>* constrain V to only accept integral types.</d=
iv><div><br></div></div><div>Observations</div><div>------------</div><div>=
<br></div><div>* is_enum() is there for people who just need to check valid=
ity and no more.</div><div>and saves the user writing redudant boiler plate=
 code that the compiler does better.</div><div>* to_enum_or_throw() is ther=
e for people who find simple works for them.</div><div>its name makes it cl=
ear that exceptions can happen.</div><div>* to_enum() is there for people w=
ho need performance and without exceptions.</div><div>* We don&#39;t depend=
 on optional.</div><div>* Means &lt;utility&gt; isn&#39;t dependent on opti=
onal if we put it there.</div><div><div>* make_bad_enum avoids making bad_e=
num a template.</div>* make_bad_enum gives us good error messages and bette=
r than bad_optional_access.</div><div>*=C2=A0make_bad_enum means=C2=A0we ca=
n=C2=A0create an=C2=A0error class=C2=A0for reporting elsewhere -=C2=A0we do=
n&#39;t have to throw it.</div><div>*=C2=A0make_bad_enum means we don&#39;t=
 expose any get enum_type_name function the reflection people will reproduc=
e.</div><div>* make_bad_enum gives people flexibility to throw when they ar=
e ready instead of forcing a throw as soon as conversion fails.</div><div>*=
 Might play well with structured bindings.</div><div><br></div><div>Main ch=
oices:</div><div>*=C2=A0We could=C2=A0model this on optional=C2=A0i.e. incl=
ude=C2=A0has_value etc.=C2=A0but it=C2=A0seems simpler not to. Either way i=
s fine to me.</div><div>I&#39;m not sure such safety is warranted and=C2=A0=
from_chars/to_chars is pretty simple too so I went that way.</div><div><div=
>* The=C2=A0caller has all the utilities here to build that or work with=C2=
=A0optional directly -=C2=A0whatever=C2=A0they need.</div><div>* I think=C2=
=A0being able to get=C2=A0good error messages on failure is important.</div=
><div>This tries to=C2=A0enable making decent errors available no matter wh=
at method or=C2=A0is used.</div><div>=C2=A0i.e. include the enum type name =
and bad value in the error.</div></div><div>* I&#39;ve=C2=A0used std::range=
_error as the exception type=C2=A0for failure but another may be appropriat=
e.</div><div>bad_enum as an exception=C2=A0type=C2=A0contains the value tha=
t was bad and the type name that it failed to convert to.</div><div>This=C2=
=A0would allow people to extract the values to construct their own error me=
ssages (perhaps in other languages like French etc.).</div><div><br></div><=
div>If std::bad_enum is too much API, that could be dropped for just std::r=
ange_error or something as long a it contains</div><div>a full description =
of the error I think that&#39;s fine.</div><div><br></div><div>I&#39;d like=
 to know what you and the=C2=A0Committee&#39;s disposition towards=C2=A0the=
se ideas and views. Hope this helps.</div><div><br></div><div>Thanks</div><=
div>GM</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/57258435-5d82-48e7-8ed7-3c38682418fb%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/57258435-5d82-48e7-8ed7-3c38682418fb=
%40isocpp.org</a>.<br />

------=_Part_2524_1908813640.1484052539793--

------=_Part_2523_1149900171.1484052539792--

.
