Skip to content

Commit 0a5e4cf

Browse files
committed
Added enum_to_string and string_to_enum
1 parent 99a294a commit 0a5e4cf

File tree

2 files changed

+105
-26
lines changed

2 files changed

+105
-26
lines changed

2996_reflection/p2996r0.html

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="utf-8" />
55
<meta name="generator" content="mpark/wg21" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
7-
<meta name="dcterms.date" content="2023-10-11" />
7+
<meta name="dcterms.date" content="2023-10-12" />
88
<title>Reflection for C++26</title>
99
<style>
1010
code{white-space: pre-wrap;}
@@ -538,7 +538,7 @@ <h1 class="title" style="text-align:center">Reflection for C++26</h1>
538538
</tr>
539539
<tr>
540540
<td>Date:</td>
541-
<td>2023-10-11</td>
541+
<td>2023-10-12</td>
542542
</tr>
543543
<tr>
544544
<td style="vertical-align:top">Project:</td>
@@ -573,6 +573,7 @@ <h1 id="toctitle">Contents</h1>
573573
<ul>
574574
<li><a href="#back-and-forth"><span class="toc-section-number">2.1</span> Back-And-Forth<span></span></a></li>
575575
<li><a href="#selecting-members"><span class="toc-section-number">2.2</span> Selecting Members<span></span></a></li>
576+
<li><a href="#enum-to-string"><span class="toc-section-number">2.3</span> Enum to String<span></span></a></li>
576577
</ul></li>
577578
<li><a href="#proposed-features"><span class="toc-section-number">3</span> Proposed Features<span></span></a>
578579
<ul>
@@ -634,6 +635,39 @@ <h2 data-number="2.2" id="selecting-members"><span class="header-section-number"
634635
<span id="cb3-13"><a href="#cb3-13"></a><span class="op">}</span></span></code></pre></div>
635636
</blockquote>
636637
<p>This example also illustrates that bit fields are not beyond the reach of this proposal.</p>
638+
<h2 data-number="2.3" id="enum-to-string"><span class="header-section-number">2.3</span> Enum to String<a href="#enum-to-string" class="self-link"></a></h2>
639+
<p>One of the most commonly requested facilities is to convert an enum value to a string (this example relies on expansion statements <span class="citation" data-cites="P1306R1">[<a href="#ref-P1306R1" role="doc-biblioref">P1306R1</a>]</span>):</p>
640+
<blockquote>
641+
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
642+
<span id="cb4-2"><a href="#cb4-2"></a> <span class="kw">requires</span> std<span class="op">::</span>is_enum_v<span class="op">&lt;</span>E<span class="op">&gt;</span></span>
643+
<span id="cb4-3"><a href="#cb4-3"></a><span class="kw">constexpr</span> std<span class="op">::</span>string enum_to_string<span class="op">(</span>E value<span class="op">)</span> <span class="op">{</span></span>
644+
<span id="cb4-4"><a href="#cb4-4"></a> <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
645+
<span id="cb4-5"><a href="#cb4-5"></a> <span class="cf">if</span> <span class="op">(</span>value <span class="op">==</span> <span class="op">[:</span>e<span class="op">:])</span> <span class="op">{</span></span>
646+
<span id="cb4-6"><a href="#cb4-6"></a> <span class="cf">return</span> std<span class="op">::</span>string<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">))</span>;</span>
647+
<span id="cb4-7"><a href="#cb4-7"></a> <span class="op">}</span></span>
648+
<span id="cb4-8"><a href="#cb4-8"></a> <span class="op">}</span></span>
649+
<span id="cb4-9"><a href="#cb4-9"></a></span>
650+
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
651+
<span id="cb4-11"><a href="#cb4-11"></a><span class="op">}</span></span>
652+
<span id="cb4-12"><a href="#cb4-12"></a></span>
653+
<span id="cb4-13"><a href="#cb4-13"></a><span class="kw">enum</span> Color <span class="op">{</span> red, green, blue <span class="op">}</span>;</span>
654+
<span id="cb4-14"><a href="#cb4-14"></a><span class="kw">static_assert</span><span class="op">(</span>enum_to_string<span class="op">(</span>Color<span class="op">::</span>red<span class="op">)</span> <span class="op">==</span> <span class="st">&quot;red&quot;</span><span class="op">)</span>;</span>
655+
<span id="cb4-15"><a href="#cb4-15"></a><span class="kw">static_assert</span><span class="op">(</span>enum_to_string<span class="op">(</span>Color<span class="op">(</span><span class="dv">42</span><span class="op">))</span> <span class="op">==</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span><span class="op">)</span>;</span></code></pre></div>
656+
</blockquote>
657+
<p>We can also do the reverse in pretty much the same way:</p>
658+
<blockquote>
659+
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
660+
<span id="cb5-2"><a href="#cb5-2"></a> <span class="kw">requires</span> std<span class="op">::</span>is_enum_v<span class="op">&lt;</span>E<span class="op">&gt;</span></span>
661+
<span id="cb5-3"><a href="#cb5-3"></a><span class="kw">constexpr</span> std<span class="op">::</span>optional<span class="op">&lt;</span>E<span class="op">&gt;</span> string_to_enum<span class="op">(</span>std<span class="op">::</span>string_view name<span class="op">)</span> <span class="op">{</span></span>
662+
<span id="cb5-4"><a href="#cb5-4"></a> <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
663+
<span id="cb5-5"><a href="#cb5-5"></a> <span class="cf">if</span> <span class="op">(</span>name <span class="op">==</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">))</span> <span class="op">{</span></span>
664+
<span id="cb5-6"><a href="#cb5-6"></a> <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>;</span>
665+
<span id="cb5-7"><a href="#cb5-7"></a> <span class="op">}</span></span>
666+
<span id="cb5-8"><a href="#cb5-8"></a> <span class="op">}</span></span>
667+
<span id="cb5-9"><a href="#cb5-9"></a></span>
668+
<span id="cb5-10"><a href="#cb5-10"></a> <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
669+
<span id="cb5-11"><a href="#cb5-11"></a><span class="op">}</span></span></code></pre></div>
670+
</blockquote>
637671
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposed-features"><span class="header-section-number">3</span> Proposed Features<a href="#proposed-features" class="self-link"></a></h1>
638672
<h2 data-number="3.1" id="the-reflection-operator"><span class="header-section-number">3.1</span> The Reflection Operator (<code class="sourceCode cpp"><span class="op">^</span></code>)<a href="#the-reflection-operator" class="self-link"></a></h2>
639673
<p>The reflection operator produces a reflection value from a grammatical construct (its operand):</p>
@@ -666,15 +700,15 @@ <h2 data-number="3.2" id="splicers"><span class="header-section-number">3.2</spa
666700
<li><code class="sourceCode cpp"><span class="op">[:</span>r<span class="op">:]::</span></code> produces a <em>nested-name-specifier</em> corresponding to the namespace, enumeration type, or class type represented by <code class="sourceCode cpp">r</code>.</li>
667701
</ul>
668702
<p>Attempting to splice a reflection value that does not meet the requirement of the splice (including “invalid reflections”) is ill-formed. For example: :::bq</p>
669-
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">typename</span><span class="op">[:</span> <span class="op">^::</span> <span class="op">:]</span> x <span class="op">=</span> <span class="dv">0</span>; <span class="co">// Error.</span></span></code></pre></div>
703+
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">typename</span><span class="op">[:</span> <span class="op">^::</span> <span class="op">:]</span> x <span class="op">=</span> <span class="dv">0</span>; <span class="co">// Error.</span></span></code></pre></div>
670704
<p>::: A quality implementation should emit the diagnostic text associated with an invalid reflection when attempting to splice that invalid reflection.</p>
671705
<h2 data-number="3.3" id="stdmetainfo"><span class="header-section-number">3.3</span> <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code><a href="#stdmetainfo" class="self-link"></a></h2>
672706
<p>The type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> can be defined as follows:</p>
673-
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
674-
<span id="cb5-2"><a href="#cb5-2"></a> <span class="kw">namespace</span> meta <span class="op">{</span></span>
675-
<span id="cb5-3"><a href="#cb5-3"></a> <span class="kw">using</span> info <span class="op">=</span> <span class="kw">decltype</span><span class="op">(^</span><span class="dt">int</span><span class="op">)</span>;</span>
676-
<span id="cb5-4"><a href="#cb5-4"></a> <span class="op">}</span></span>
677-
<span id="cb5-5"><a href="#cb5-5"></a><span class="op">}</span></span></code></pre></div>
707+
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
708+
<span id="cb7-2"><a href="#cb7-2"></a> <span class="kw">namespace</span> meta <span class="op">{</span></span>
709+
<span id="cb7-3"><a href="#cb7-3"></a> <span class="kw">using</span> info <span class="op">=</span> <span class="kw">decltype</span><span class="op">(^</span><span class="dt">int</span><span class="op">)</span>;</span>
710+
<span id="cb7-4"><a href="#cb7-4"></a> <span class="op">}</span></span>
711+
<span id="cb7-5"><a href="#cb7-5"></a><span class="op">}</span></span></code></pre></div>
678712
<p>In our initial proposal a value of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> can represent:</p>
679713
<ul>
680714
<li>an error (corresponding to an “invalid reflection”)</li>
@@ -688,31 +722,31 @@ <h2 data-number="3.3" id="stdmetainfo"><span class="header-section-number">3.3</
688722
</ul>
689723
<p>Notably absent at this time are general non-constant expressions (that aren’t <em>expression-id</em>s referring to variables or structured bindings). For example:</p>
690724
<blockquote>
691-
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span>;</span>
692-
<span id="cb6-2"><a href="#cb6-2"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
693-
<span id="cb6-3"><a href="#cb6-3"></a> <span class="op">[:^</span>x<span class="op">:]</span> <span class="op">=</span> <span class="dv">42</span>; <span class="co">// Okay. Same as: x = 42;</span></span>
694-
<span id="cb6-4"><a href="#cb6-4"></a> x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>x<span class="op">):]</span>; <span class="co">// Error: &quot;2*x&quot; is a general non-constant expression.</span></span>
695-
<span id="cb6-5"><a href="#cb6-5"></a> <span class="kw">constexpr</span> <span class="dt">int</span> N <span class="op">=</span> <span class="dv">42</span>;</span>
696-
<span id="cb6-6"><a href="#cb6-6"></a> x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>N<span class="op">):]</span>; <span class="co">// Okay: &quot;2*N&quot; is a constant-expression.</span></span>
697-
<span id="cb6-7"><a href="#cb6-7"></a><span class="op">}</span></span></code></pre></div>
725+
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span>;</span>
726+
<span id="cb8-2"><a href="#cb8-2"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
727+
<span id="cb8-3"><a href="#cb8-3"></a> <span class="op">[:^</span>x<span class="op">:]</span> <span class="op">=</span> <span class="dv">42</span>; <span class="co">// Okay. Same as: x = 42;</span></span>
728+
<span id="cb8-4"><a href="#cb8-4"></a> x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>x<span class="op">):]</span>; <span class="co">// Error: &quot;2*x&quot; is a general non-constant expression.</span></span>
729+
<span id="cb8-5"><a href="#cb8-5"></a> <span class="kw">constexpr</span> <span class="dt">int</span> N <span class="op">=</span> <span class="dv">42</span>;</span>
730+
<span id="cb8-6"><a href="#cb8-6"></a> x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>N<span class="op">):]</span>; <span class="co">// Okay: &quot;2*N&quot; is a constant-expression.</span></span>
731+
<span id="cb8-7"><a href="#cb8-7"></a><span class="op">}</span></span></code></pre></div>
698732
</blockquote>
699733
<p>Note that for <code class="sourceCode cpp"><span class="op">^(</span><span class="dv">2</span><span class="op">*</span>N<span class="op">)</span></code> an implementation only has to capture the constant value of <code class="sourceCode cpp"><span class="dv">2</span><span class="op">*</span>N</code> and not various other properties of the underlying expression (such as any temporaries it involves, etc.).</p>
700734
<p>The type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> is a <em>scalar</em> type. Nontype template arguments of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> are permitted. The entity being reflected can affect the linkage of a template instance involving a reflection. For example:</p>
701735
<blockquote>
702-
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> R<span class="op">&gt;</span> <span class="kw">struct</span> S <span class="op">{}</span>;</span>
703-
<span id="cb7-2"><a href="#cb7-2"></a></span>
704-
<span id="cb7-3"><a href="#cb7-3"></a><span class="kw">extern</span> <span class="dt">int</span> x;</span>
705-
<span id="cb7-4"><a href="#cb7-4"></a><span class="kw">static</span> <span class="dt">int</span> y;</span>
706-
<span id="cb7-5"><a href="#cb7-5"></a></span>
707-
<span id="cb7-6"><a href="#cb7-6"></a>S<span class="op">&lt;^</span>x<span class="op">&gt;</span> sx; <span class="co">// S&lt;^x&gt; has external name linkage.</span></span>
708-
<span id="cb7-7"><a href="#cb7-7"></a>S<span class="op">&lt;^</span>y<span class="op">&gt;</span> sy; <span class="co">// S&lt;^y&gt; has internal name linkage.</span></span></code></pre></div>
736+
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> R<span class="op">&gt;</span> <span class="kw">struct</span> S <span class="op">{}</span>;</span>
737+
<span id="cb9-2"><a href="#cb9-2"></a></span>
738+
<span id="cb9-3"><a href="#cb9-3"></a><span class="kw">extern</span> <span class="dt">int</span> x;</span>
739+
<span id="cb9-4"><a href="#cb9-4"></a><span class="kw">static</span> <span class="dt">int</span> y;</span>
740+
<span id="cb9-5"><a href="#cb9-5"></a></span>
741+
<span id="cb9-6"><a href="#cb9-6"></a>S<span class="op">&lt;^</span>x<span class="op">&gt;</span> sx; <span class="co">// S&lt;^x&gt; has external name linkage.</span></span>
742+
<span id="cb9-7"><a href="#cb9-7"></a>S<span class="op">&lt;^</span>y<span class="op">&gt;</span> sy; <span class="co">// S&lt;^y&gt; has internal name linkage.</span></span></code></pre></div>
709743
</blockquote>
710744
<p>Namespace <code class="sourceCode cpp">std<span class="op">::</span>meta</code> is associated with type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>: That allows the core meta functions to be invoked without explicit qualification. For example:</p>
711745
<blockquote>
712-
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
713-
<span id="cb8-2"><a href="#cb8-2"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
714-
<span id="cb8-3"><a href="#cb8-3"></a>std<span class="op">::</span>string name2 <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(^</span>S<span class="op">)</span>; <span class="co">// Okay.</span></span>
715-
<span id="cb8-4"><a href="#cb8-4"></a>std<span class="op">::</span>string name1 <span class="op">=</span> name_of<span class="op">(^</span>S<span class="op">)</span>; <span class="co">// Also okay.</span></span></code></pre></div>
746+
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
747+
<span id="cb10-2"><a href="#cb10-2"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
748+
<span id="cb10-3"><a href="#cb10-3"></a>std<span class="op">::</span>string name2 <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(^</span>S<span class="op">)</span>; <span class="co">// Okay.</span></span>
749+
<span id="cb10-4"><a href="#cb10-4"></a>std<span class="op">::</span>string name1 <span class="op">=</span> name_of<span class="op">(^</span>S<span class="op">)</span>; <span class="co">// Also okay.</span></span></code></pre></div>
716750
</blockquote>
717751
<h2 data-number="3.4" id="metafunctions"><span class="header-section-number">3.4</span> Metafunctions<a href="#metafunctions" class="self-link"></a></h2>
718752
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">4</span> References<a href="#bibliography" class="self-link"></a></h1>
@@ -721,6 +755,10 @@ <h1 data-number="4" style="border-bottom:1px solid #cccccc" id="bibliography"><s
721755
<p>[P1240R2] Daveed Vandevoorde, Wyatt Childers, Andrew Sutton, Faisal Vali. 2022-01-14. Scalable Reflection. <br />
722756
<a href="https://wg21.link/p1240r2">https://wg21.link/p1240r2</a></p>
723757
</div>
758+
<div id="ref-P1306R1">
759+
<p>[P1306R1] Andrew Sutton, Sam Goodrick, Daveed Vandevoorde. 2019-01-21. Expansion statements. <br />
760+
<a href="https://wg21.link/p1306r1">https://wg21.link/p1306r1</a></p>
761+
</div>
724762
<div id="ref-P2237R0">
725763
<p>[P2237R0] Andrew Sutton. 2020-10-15. Metaprogramming. <br />
726764
<a href="https://wg21.link/p2237r0">https://wg21.link/p2237r0</a></p>

0 commit comments

Comments
 (0)