mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 08:46:42 +08:00
Project site
This commit is contained in:
commit
5cfa84f1b8
343
ApiReference.html
Normal file
343
ApiReference.html
Normal file
@ -0,0 +1,343 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>API reference - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/ApiReference.html" />
|
||||
<meta name="description" content="Detailed description of the Better Enums API." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="api">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>API reference</h2>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#Overview">Overview</a></li><li><a href="#RunningExample">Running example</a></li><li><a href="#HelperFunctionsAndTypes">Helper functions and types</a><ul><li><a href="#Typedef_enumerated">typedef _enumerated</a></li><li><a href="#Operator+">operator +</a></li><li><a href="#ConstructorEnum_enumerated">constructor Enum(_enumerated)</a></li><li><a href="#StructBetter_enumsoptional">struct better_enums::optional</a></li></ul></li><li><a href="#ValueCountAndIteration">Value count and iteration</a><ul><li><a href="#_size">_size</a></li><li><a href="#_size_constant">_size_constant</a></li><li><a href="#Typedef_value_iterable">typedef _value_iterable</a></li><li><a href="#Typedef_value_iterator">typedef _value_iterator</a></li><li><a href="#_values">_values</a></li></ul></li><li><a href="#StringConversionAndIteration">String conversion and iteration</a><ul><li><a href="#_to_string">_to_string</a></li><li><a href="#_from_string">_from_string</a></li><li><a href="#_from_string_nothrow">_from_string_nothrow</a></li><li><a href="#_from_string_nocase">_from_string_nocase</a></li><li><a href="#_from_string_nocase_nothrow">_from_string_nocase_nothrow</a></li><li><a href="#_is_validconstChar*">_is_valid(const char*)</a></li><li><a href="#_is_valid_nocase">_is_valid_nocase</a></li><li><a href="#_name">_name</a></li><li><a href="#Typedef_name_iterable">typedef _name_iterable</a></li><li><a href="#Typedef_name_iterator">typedef _name_iterator</a></li><li><a href="#_names">_names</a></li></ul></li><li><a href="#IntegerConversion">Integer conversion</a><ul><li><a href="#Typedef_integral">typedef _integral</a></li><li><a href="#_to_integral">_to_integral</a></li><li><a href="#_from_integral">_from_integral</a></li><li><a href="#_from_integral_nothrow">_from_integral_nothrow</a></li><li><a href="#_from_integral_unchecked">_from_integral_unchecked</a></li><li><a href="#_is_valid_integral">_is_valid(_integral)</a></li></ul></li><li><a href="#IndexLookup">Index lookup</a><ul><li><a href="#_to_index">_to_index</a></li><li><a href="#_from_index">_from_index</a></li><li><a href="#_from_index_unchecked">_from_index_unchecked</a></li><li><a href="#_from_index_nothrow">_from_index_nothrow</a></li></ul></li><li><a href="#StreamOperators">Stream operators</a><ul><li><a href="#Operator<<">operator <<</a></li><li><a href="#Operator>>">operator >></a></li></ul></li><li><a href="#Hashing">Hashing</a><ul><li><a href="#Better_enums_declare_std_hash">BETTER_ENUMS_DECLARE_STD_HASH</a></li></ul></li></ul></p>
|
||||
<a id="Overview"></a><h3>Overview</h3>
|
||||
<p>The declaration</p>
|
||||
<pre>#include <enum.h>
|
||||
<em>BETTER_ENUM</em>(<em>Enum</em>, <em>underlying_type</em>, <em>A</em>, <em>B</em>, <em>C</em>, ...)</pre><p>generates a new class type <code>Enum</code> which is notionally similar to the type
|
||||
created by this <span class="cpp">C++</span><span class="eleven">11</span> declaration:</p>
|
||||
<pre class="comment"><em>enum class Enum</em> : <em>underlying_type</em> {<em>A</em>, <em>B</em>, <em>C</em>, ...};</pre><p>That is, <code>Enum</code> is a scoped enumerated type with constants <code>Enum::A</code>, <code>Enum::B</code>,
|
||||
<code>Enum::C</code>, and so on, with memory representation the same as <code>underlying_type</code>.
|
||||
It is possible to supply initializers for any of the constants:</p>
|
||||
<pre><em>BETTER_ENUM</em>(Enum, underlying_type, <em>A</em> = <em>1</em>, <em>B</em> = <em>constant_expression</em>, <em>C</em> = <em>A</em>, ...)</pre><p>The initializers have the same meaning and constraints as in a built-in <code>enum</code>
|
||||
or <code>enum class</code> declaration.</p>
|
||||
<hr>
|
||||
<p>The principal differences between the types declared by the <code>BETTER_ENUM</code> macro
|
||||
and <code>enum class</code> are:</p>
|
||||
<ul>
|
||||
<li><code>BETTER_ENUM</code> is available for <span class="cpp">C++</span><span class="eleven">98</span>
|
||||
<a href="CompilerSupport.html">compilers</a> supporting <code>__VA_ARGS__</code> —
|
||||
all major compilers — while <code>enum class</code> is restricted to <span class="cpp">C++</span><span class="eleven">11</span>,</li>
|
||||
<li>the <code>BETTER_ENUM</code> type is implicitly convertible to integral types, though
|
||||
this can be <a href="OptInFeatures.html#StrictConversions">disabled</a> when
|
||||
using <span class="cpp">C++</span><span class="eleven">11</span>, and</li>
|
||||
<li>the <code>BETTER_ENUM</code> type supports a set of reflective operations, detailed in
|
||||
the rest of this reference.</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>The types produced by the <code>BETTER_ENUM</code> macro are called <em>Better Enums</em> in the
|
||||
rest of this reference.</p>
|
||||
<p>Better Enums are similar to their underlying type for the purposes of argument
|
||||
passing. This means that they typically fit into a machine word, and should be
|
||||
passed by value.</p>
|
||||
<p>All names declared in the scope of a Better Enum are prefixed with an underscore
|
||||
in order to avoid conflicts with potential constant names.</p>
|
||||
<a id="RunningExample"></a><h3>Running example</h3>
|
||||
<p>The rest of this reference uses the following declaration as a running example:</p>
|
||||
<pre><em>BETTER_ENUM</em>(<em>Enum</em>, <em>int</em>, <em>A</em>, <em>B</em>, <em>C</em>)</pre><a id="HelperFunctionsAndTypes"></a><h3>Helper functions and types</h3>
|
||||
<p>The types and functions described here make it possible to use Better Enums with
|
||||
the rest of <span class="cpp">C++</span> in a reasonable fashion, or else they are referenced in the
|
||||
rest of the documentation.</p>
|
||||
<a id="Typedef_enumerated"></a><h4><em>typedef _enumerated</em></h4>
|
||||
<p>An internal type used to declare constants. The <code>BETTER_ENUM</code> macro generates
|
||||
something similar to</p>
|
||||
<pre class="comment"><em>struct Enum</em> {
|
||||
<em>enum _enumerated</em> : <em>int</em> {<em>A</em>, <em>B</em>, <em>C</em>};
|
||||
// ...
|
||||
};</pre><p>The user needs to be aware of <code>_enumerated</code> in only one situation. A literal
|
||||
constant such as <code>Enum::A</code> is an expression of type <code>Enum::_enumerated</code>, not
|
||||
<code>Enum</code>. It is not possible to directly call a method on the constant, as in
|
||||
<code>Enum::A._to_string()</code>. This problem is addressed by operator <code>+</code>
|
||||
<a href="#Operator+">below</a>.</p>
|
||||
<a id="Operator+"></a><h4>non-member constexpr Enum unary <em>operator +</em>(_enumerated)</h4>
|
||||
<p>Forces promotion of <a href="#Typedef_enumerated"><code>Enum::_enumerated</code></a> to <code>Enum</code>.
|
||||
Provided to solve the problem described <a href="#Typedef_enumerated">above</a>. So:</p>
|
||||
<pre>// Does not compile
|
||||
<em>Enum::A</em>.<em>_to_string</em>()
|
||||
|
||||
// Compiles
|
||||
(<em>+Enum::A</em>).<em>_to_string</em>()</pre><a id="ConstructorEnum_enumerated"></a><h4>constexpr implicit <em>constructor Enum(_enumerated)</em></h4>
|
||||
<p>A constructor that performs implicit conversions of
|
||||
<a href="#Typedef_enumerated"><code>Enum::_enumerated</code></a> to <code>Enum</code>. This allows code to use a
|
||||
literal constant where <code>Enum</code> is expected, and the compiler can do an implicit
|
||||
conversion. For example:</p>
|
||||
<pre>void <em>do_something</em>(<em>Enum value</em>);
|
||||
|
||||
do_something(<em>+Enum::A</em>); // Not necessary
|
||||
do_something(<em>Enum::A</em>); // Implicit conversion available
|
||||
|
||||
<em>Enum value</em> = <em>Enum::A</em>; // Implicit conversion</pre><p>The other constructors of <code>Enum</code> are the implicitly-generated copy and move
|
||||
constructors. There is no default constructor. If you have comments on what a
|
||||
default constructor should do, please <a href="Contact.html">let me know</a>.</p>
|
||||
<a id="StructBetter_enumsoptional"></a><h4>non-member <em>struct better_enums::optional</em><Enum></h4>
|
||||
<p>An optional <code>Enum</code> value. These are returned by the various <code>_nothrow</code>
|
||||
functions, such as <a href="#_from_string_nothrow"><code>_from_string_nothrow</code></a>. This type is
|
||||
meant to represent the possibility of failure. For example, suppose you have:</p>
|
||||
<pre><em>better_enums::optional</em><<em>Enum</em>> <em>maybe</em> = <em>_from_string_nothrow</em>(<em>"A"</em>);</pre><p>An optional value such as <code>maybe</code> is convertible to <code>bool</code>. If it converts to
|
||||
<code>true</code>, it holds a valid <code>Enum</code> value. Otherwise, if it converts to <code>false</code>, the
|
||||
operation that produced the optional value failed. So, you can continue with</p>
|
||||
<pre><em>if</em> (<em>maybe</em>) {
|
||||
// The string conversion succeeded
|
||||
do_something(<em>*maybe</em>);
|
||||
}
|
||||
<em>else</em> {
|
||||
// The string conversion failed
|
||||
}</pre><p>As you can see, <code>*maybe</code> evaluates to the <code>Enum</code> value, in this case <code>Enum::A</code>.</p>
|
||||
<p>The rest of this reference refers to this type as simply <code>optional</code>, as if you
|
||||
had entered</p>
|
||||
<pre class="comment">using <em>optional</em> = <em>better_enums::optional</em><<em>Enum</em>>;</pre><a id="ValueCountAndIteration"></a><h3>Value count and iteration</h3>
|
||||
<p>The types and members described here have to do with the sequence of constants
|
||||
declared, i.e. <code>A</code>, <code>B</code>, <code>C</code> in the <a href="#RunningExample">running example</a>.</p>
|
||||
<a id="_size"></a><h4>static constexpr size_t <em>_size</em>()</h4>
|
||||
<p>The number of constants declared. <code>Enum::_size() == 3</code>.</p>
|
||||
<a id="_size_constant"></a><h4>static constexpr const size_t <em>_size_constant</em></h4>
|
||||
<p>Same as <a href="#_size"><code>_size</code></a>, but a constant instead of a function. This is
|
||||
provided for use in <span class="cpp">C++</span><span class="eleven">98</span> constant expressions.</p>
|
||||
<a id="Typedef_value_iterable"></a><h4><em>typedef _value_iterable</em></h4>
|
||||
<p>Type of object that permits iteration over the constants. Has at least
|
||||
<code>constexpr</code> <code>begin()</code>, <code>end()</code>, and <code>size()</code> methods, and <code>constexpr</code>
|
||||
<code>operator[]</code>. Iteration visits each <em>declared</em> constant, even if multiple
|
||||
constants have the same value, and visits them in order of declaration. See
|
||||
usage examples under <a href="#_values"><code>_values</code></a>.</p>
|
||||
<a id="Typedef_value_iterator"></a><h4><em>typedef _value_iterator</em></h4>
|
||||
<p>Random-access iterator type for <a href="#_value_iterable"><code>_value_iterable</code></a>. Most
|
||||
operations, including dereferencing, are <code>constexpr</code>. The exceptions are
|
||||
mutating operators such as <code>operator++</code>. In <code>constexpr</code> code, that can be
|
||||
replaced with addition of <code>1</code>. You typically don't have to refer to this type
|
||||
directly.</p>
|
||||
<a id="_values"></a><h4>static constexpr _value_iterable <em>_values</em>()</h4>
|
||||
<p><code>constexpr</code> access to the sequence of declared constants. For example:</p>
|
||||
<pre><em>for</em> (size_t index = 0; <em>index</em> < <em>Enum::_values().size()</em>; ++index)
|
||||
do_something(<em>Enum::_values()[index]</em>);</pre><p>or, using iterators:</p>
|
||||
<pre><em>for</em> (Enum::_value_iterator iterator = <em>Enum::_values().begin()</em>;
|
||||
iterator != <em>Enum::_values().end()</em>; ++iterator) {
|
||||
|
||||
do_something(<em>*iterator</em>);
|
||||
}</pre><p>or, in <span class="cpp">C++</span><span class="eleven">11</span>:</p>
|
||||
<pre><em>for</em> (Enum value : <em>Enum::_values()</em>)
|
||||
do_something(<em>value</em>);</pre><a id="StringConversionAndIteration"></a><h3>String conversion and iteration</h3>
|
||||
<a id="_to_string"></a><h4>member constexpr? const char* <em>_to_string</em>() const</h4>
|
||||
<p>Returns the string representation a Better Enum value. For example:</p>
|
||||
<pre>Enum value = <em>Enum::A</em>;
|
||||
value.<em>_to_string</em>(); // Same as "A".</pre><p>If two or more constants have the same numeric value, it is undefined which name
|
||||
<code>_to_string</code> will choose, but it will choose one of them.</p>
|
||||
<p>If <code>value</code> is not equal to the representation of any declared constant, for
|
||||
example if it was obtained using an unchecked conversion such as</p>
|
||||
<pre>Enum value = <em>Enum::_from_integral_unchecked</em>(<em>0xbadc0de</em>);</pre><p>then the behavior of <code>value._to_string</code> is undefined.</p>
|
||||
<p>Running time is linear in the number of declared constants.</p>
|
||||
<p>This method is not <code>constexpr</code> by default. Read
|
||||
<a href="OptInFeatures.html#CompileTimeNameTrimming">here</a> for information
|
||||
about making it <code>constexpr</code>.</p>
|
||||
<a id="_from_string"></a><h4>static constexpr Enum <em>_from_string</em>(const char*)</h4>
|
||||
<p>If the given string is the exact name of a declared constant, returns the
|
||||
constant. Otherwise, throws <code>std::runtime_error</code>. Running time is linear in the
|
||||
number of declared constants multiplied by the length of the longest constant.</p>
|
||||
<a id="_from_string_nothrow"></a><h4>static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)</h4>
|
||||
<p>Same as <a href="#_from_string"><code>_from_string</code></a>, but does not throw an exception on
|
||||
failure. Returns an <a href="#StructBetter_enumsoptional">optional value</a> instead.</p>
|
||||
<a id="_from_string_nocase"></a><h4>static constexpr Enum <em>_from_string_nocase</em>(const char*)</h4>
|
||||
<p>Same as <a href="#_from_string"><code>_from_string</code></a>, but comparison is up to case, in the
|
||||
usual sense in the Latin-1 encoding.</p>
|
||||
<a id="_from_string_nocase_nothrow"></a><h4>static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)</h4>
|
||||
<p>Is to <a href="#_from_string_nocase"><code>_from_string_nocase</code></a> as
|
||||
<a href="#_from_string_nothrow"><code>_from_string_nothrow</code></a> is to
|
||||
<a href="#_from_string"><code>_from_string</code></a>.</p>
|
||||
<a id="_is_validconstChar*"></a><h4>static constexpr bool <em>_is_valid(const char*)</em></h4>
|
||||
<p>Evaluates to <code>true</code> if and only if the given string is the exact name of a
|
||||
declared constant. Running time is the same as for
|
||||
<a href="#_from_string"><code>_from_string</code></a>.</p>
|
||||
<a id="_is_valid_nocase"></a><h4>static constexpr bool <em>_is_valid_nocase</em>(const char*)</h4>
|
||||
<p>The same as <a href="#_is_validconstChar*"><code>_is_valid</code></a>, but comparison is done up to
|
||||
case as in <a href="#_from_string_nocase"><code>_from_string_nocase</code></a>.</p>
|
||||
<a id="_name"></a><h4>static constexpr const char* <em>_name</em>()</h4>
|
||||
<p>Evaluates to the name of the Better Enum type. <code>Enum::_name()</code> is the same
|
||||
string as <code>"Enum"</code>.</p>
|
||||
<a id="Typedef_name_iterable"></a><h4><em>typedef _name_iterable</em></h4>
|
||||
<p>Type of object that permits iteration over names of declared constants. Has at
|
||||
least <code>constexpr</code> <code>begin()</code>, <code>end()</code>, and <code>size()</code> methods. <code>operator[]</code> is also
|
||||
available, but is <code>constexpr</code> if and only if <a href="#_to_string"><code>_to_string</code></a> is
|
||||
<code>constexpr</code>. Iteration visits constants in order of declaration. See usage
|
||||
example under <a href="#_names"><code>_names</code></a>.</p>
|
||||
<a id="Typedef_name_iterator"></a><h4><em>typedef _name_iterator</em></h4>
|
||||
<p>Random-access iterator type for <code>_name_iterable</code>. Most operations are
|
||||
<code>constexpr</code>, but dereferencing is <code>constexpr</code> if and only if
|
||||
<a href="#_to_string"><code>_to_string</code></a> is <code>constexpr</code>. Mutating operators such as
|
||||
<code>operator++</code> are not <code>constexpr</code> due to their nature — adding <code>1</code> is a
|
||||
<code>constexpr</code> alternative. You typically don't have to refer to this type
|
||||
directly.</p>
|
||||
<a id="_names"></a><h4>static constexpr? _name_iterable <em>_names</em>()</h4>
|
||||
<p>Access to the sequence of declared constant names. For example:</p>
|
||||
<pre><em>for</em> (size_t index = 0; <em>index</em> < <em>Enum::_names().size()</em>; ++index)
|
||||
std::cout << <em>Enum::_names()[index]</em> << std::endl;</pre><p>or, using iterators:</p>
|
||||
<pre><em>for</em> (Enum::_name_iterator iterator = <em>Enum::_names().begin()</em>;
|
||||
iterator != <em>Enum::_names().end()</em>; ++iterator) {
|
||||
|
||||
std::cout << <em>*iterator</em> << std::endl;
|
||||
}</pre><p>or, in <span class="cpp">C++</span><span class="eleven">11</span>:</p>
|
||||
<pre><em>for</em> (const char *name : <em>Enum::_names()</em>)
|
||||
std::cout << <em>name</em> << std::endl;</pre><p><code>constexpr</code> if and only if <a href="#_to_string"><code>_to_string</code></a> is <code>constexpr</code>.</p>
|
||||
<a id="IntegerConversion"></a><h3>Integer conversion</h3>
|
||||
<p>Better Enums are already represented as integers at run time. Values of the
|
||||
<a href="#RunningExample">running example</a> type <code>Enum</code> are the same as <code>ints</code>. However,
|
||||
<code>Enum</code> is a distinct type from <code>int</code> during type checking, the main difference
|
||||
being that its range of valid values is restricted to only the ones you have
|
||||
declared.</p>
|
||||
<p>This section describes the various translations between <code>Enum</code> and <code>int</code> that
|
||||
are available. Each one translates the type, but at run time, most are no-ops,
|
||||
or validity checks followed by no-ops.</p>
|
||||
<a id="Typedef_integral"></a><h4><em>typedef _integral</em></h4>
|
||||
<p>The <em>underlying</em> or <em>representation</em> type of the Better Enum. For example,
|
||||
<code>Enum::_integral</code> is the same type as <code>int</code>. Each Better Enum has the same size
|
||||
and alignment requirement as its representation type.</p>
|
||||
<a id="_to_integral"></a><h4>member constexpr _integral <em>_to_integral</em>() const</h4>
|
||||
<p>No-op conversion of a Better Enum to a value of its representation type. For
|
||||
example,</p>
|
||||
<pre>(+<em>Enum::C</em>)<em>._to_integral</em>() == <em>2</em></pre><p>Note that Better Enums are already implicitly convertible to their underlying
|
||||
integral types <a href="OptInFeatures.html#StrictConversions">by default</a>.
|
||||
You may still want to use this function, however, for clarity, and to ensure
|
||||
that your code remains compatible if the strict conversions feature is enabled
|
||||
later.</p>
|
||||
<a id="_from_integral"></a><h4>static constexpr Enum <em>_from_integral</em>(_integral)</h4>
|
||||
<p>Checked conversion of an integer to a Better Enum value. The check runs in time
|
||||
linear in the number of declared constants, but the conversion itself is a
|
||||
no-op. Throws <code>std::runtime_error</code> if the given integer is not the numeric value
|
||||
of one of the declared constants.</p>
|
||||
<pre><em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
||||
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error</pre><a id="_from_integral_nothrow"></a><h4>static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)</h4>
|
||||
<p>Checked conversion as <a href="#_from_integral"><code>_from_integral</code></a>, but does not throw an
|
||||
exception on failure. Returns an <a href="#StructBetter_enumsoptional">optional value</a>
|
||||
instead.</p>
|
||||
<a id="_from_integral_unchecked"></a><h4>static constexpr Enum <em>_from_integral_unchecked</em>(_integral)</h4>
|
||||
<p>No-op unchecked conversion of an integer to a Better Enum value. If the given
|
||||
integer is not the numeric value of one of the declared constants, the behavior
|
||||
of all subsequent operations on the Better Enum value is undefined.</p>
|
||||
<p>This is the direct inverse of <a href="#_to_integral"><code>_to_integral</code></a>. Here are no-op
|
||||
round trips between <code>int</code> and <code>Enum</code>:</p>
|
||||
<pre><em>Enum::_from_integral_unchecked</em>(value.<em>_to_integral</em>());
|
||||
<em>Enum::_from_integral_unchecked</em>(integer).<em>_to_integral</em>();</pre><p>You should not use this function on untrusted input, however.</p>
|
||||
<a id="_is_valid_integral"></a><h4>static constexpr bool <em>_is_valid(_integral)</em></h4>
|
||||
<p>Evaluates to <code>true</code> if and only if the given integer is the numeric value of one
|
||||
of the declared constants. Running time is linear in the number of declared
|
||||
constants.</p>
|
||||
<a id="IndexLookup"></a><h3>Index lookup</h3>
|
||||
<a id="_to_index"></a><h4>member constexpr std::size_t <em>_to_index</em>() const</h4>
|
||||
<p>Returns the index of a Better Enum value within its enum declaration. The index
|
||||
is determined from the value only; if two constants in the declaration have the
|
||||
same value, this function may return the index of either constant.</p>
|
||||
<p>If the value does not correspond to any constant in the declaration (for
|
||||
example, if it was obtained using an unchecked conversion or a cast), then the
|
||||
behavior of <code>value._to_index</code> is undefined.</p>
|
||||
<a id="_from_index"></a><h4>static constexpr Enum <em>_from_index</em>(size_t)</h4>
|
||||
<p>Returns the value of the constant with the given index. Throws
|
||||
<code>std::runtime_error</code> if not given the index of one of the constants.</p>
|
||||
<a id="_from_index_unchecked"></a><h4>static constexpr Enum <em>_from_index_unchecked</em>(size_t)</h4>
|
||||
<p>Returns the value of the constant with the given index. If not given one of the
|
||||
constants in the declaration of the enum, the returned value is undefined.</p>
|
||||
<a id="_from_index_nothrow"></a><h4>static constexpr optional<Enum> <em>_from_index_nothrow</em>(size_t)</h4>
|
||||
<p>Returns the value of the constant with the given index.</p>
|
||||
<a id="StreamOperators"></a><h3>Stream operators</h3>
|
||||
<a id="Operator<<"></a><h4>non-member std::ostream& <em>operator <<</em>(std::ostream&, const Enum&)</h4>
|
||||
<p>Formats the given enum to the given stream in the same way as
|
||||
<a href="#_to_string"><code>_to_string</code></a>.</p>
|
||||
<a id="Operator>>"></a><h4>non-member std::istream& <em>operator >></em>(std::istream&, Enum&)</h4>
|
||||
<p>Reads from the given stream and attempts to parse an enum value in the same way
|
||||
as <a href="#_from_string"><code>_from_string</code></a>. In case of failure, sets the stream's
|
||||
<code>failbit</code>.</p>
|
||||
<a id="Hashing"></a><h3>Hashing</h3>
|
||||
<a id="Better_enums_declare_std_hash"></a><h4>macro <em>BETTER_ENUMS_DECLARE_STD_HASH</em>(Enum)</h4>
|
||||
<p>Use this outside namespace scope to declare a specialization of <code>std::hash</code> for
|
||||
the type <code>Enum</code>. For example:</p>
|
||||
<pre>// This declaration might be inside a namespace.
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
|
||||
|
||||
// Later, outside the namespace:
|
||||
<em>BETTER_ENUMS_DECLARE_STD_HASH</em>(<em>Channel</em>)</pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
205
CompilerSupport.html
Normal file
205
CompilerSupport.html
Normal file
@ -0,0 +1,205 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Compiler support - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/CompilerSupport.html" />
|
||||
<meta name="description" content="Better Enums compiler support, compatibility, feature detection, and automated
|
||||
testing." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Compiler support</h2>
|
||||
<p>Better Enums aims to support all major compilers. It is known to work on:</p>
|
||||
<ul>
|
||||
<li>clang 3.3 to 3.9</li>
|
||||
<li>gcc 4.3 to 5.3</li>
|
||||
<li>Visual C++ 2008 to 2015.</li>
|
||||
</ul>
|
||||
<p>The library can be used with any compiler that supports either <span class="cpp">C++</span><span class="eleven">11</span>, or <span class="cpp">C++</span><span class="eleven">98</span>
|
||||
with the <code>__VA_ARGS__</code> extension. This includes every version of gcc and clang I
|
||||
have ever heard of, and Visual C++ down to 2005.</p>
|
||||
<p>To ensure that nothing is broken, every release of Better Enums is
|
||||
<a href="https://github.com/aantron/better-enums/tree/master/test">tested</a> in multiple configuratins on the compilers
|
||||
listed above. Testing includes the code in the tutorials, the unit tests, and a
|
||||
multiple translation unit linking test. The full list of tested compilers and
|
||||
configurations is given at <a href="#TestedConfigurations">the end of this page</a>.</p>
|
||||
<a id="CompileTimeReflectionConfigurations"></a><h3>Compile-time reflection configurations</h3>
|
||||
<p>Read this section if:</p>
|
||||
<ul>
|
||||
<li>you want to use Better Enums reflection at compile time, and need to know
|
||||
exactly what features are supported on your compiler, or</li>
|
||||
<li>Better Enums is choosing the wrong configuration automatically and you need
|
||||
to force a different choice.</li>
|
||||
</ul>
|
||||
<p>All features of Better Enums are always available for run-time use. However, for
|
||||
compile-time use, Better Enums has two main configurations: <span class="cpp">C++</span><span class="eleven">98</span> mode and
|
||||
<code>constexpr</code> mode. Better Enums tries to detect which compiler is compiling it
|
||||
and select the appropriate mode.</p>
|
||||
<p>For performance reasons, <code>constexpr</code> mode is subdivided into a "fast"
|
||||
<code>constexpr</code> mode and an
|
||||
<a href="OptInFeatures.html#CompileTimeNameTrimming">opt-in</a> "full" (slow)
|
||||
<code>constexpr</code> mode. The three modes can be ranked, with each next mode including
|
||||
all the features of the preceding ones:</p>
|
||||
<ul>
|
||||
<li><span class="cpp">C++</span><span class="eleven">98</span></li>
|
||||
<li>fast <code>constexpr</code></li>
|
||||
<li>full <code>constexpr</code></li>
|
||||
</ul>
|
||||
<p>Only <code>_size</code> is supported at compile time in <span class="cpp">C++</span><span class="eleven">98</span> mode. Fast <code>constexpr</code> mode
|
||||
adds all other members besides <code>_to_string</code> and <code>_names</code>. Full <code>constexpr</code> mode
|
||||
supports those at compile time as well.</p>
|
||||
<hr>
|
||||
<p>The mode selection code works as follows:</p>
|
||||
<ul>
|
||||
<li>First, as of the time of this writing, only clang and gcc support
|
||||
<code>constexpr</code>. So, if you are using any other compiler, Better Enums is in
|
||||
<span class="cpp">C++</span><span class="eleven">98</span> mode.</li>
|
||||
<li>If you are using gcc 4.7 or higher or clang, Better Enums uses those
|
||||
compilers' predefined macros to detect whether <code>constexpr</code> support is
|
||||
enabled with compiler flags. If so, it is in one of the <code>constexpr</code> mode.
|
||||
Otherwise, it falls back to <span class="cpp">C++</span><span class="eleven">98</span> mode.</li>
|
||||
<li>The default <code>constexpr</code> mode is fast <code>constexpr</code>. If you want to enable
|
||||
full <code>constexpr</code> mode for some or all of your enums, follow
|
||||
<a href="OptInFeatures.html#CompileTimeNameTrimming">these</a> instructions.</li>
|
||||
</ul>
|
||||
<p>If Better Enums picks the wrong mode, you can force <code>constexpr</code> mode by defining
|
||||
<code>BETTER_ENUMS_CONSTEXPR</code> before including <code>enum.h</code>, typically by passing an
|
||||
option to your compiler, or you can force <span class="cpp">C++</span><span class="eleven">98</span> mode by defining
|
||||
<code>BETTER_ENUMS_NO_CONSTEXPR</code>.</p>
|
||||
<p>If you are using a compiler for which Better Enums makes the wrong choice,
|
||||
please <a href="Contact.html">let me know</a>. I will fix it and you won't have to
|
||||
define these macros anymore.</p>
|
||||
<a id="TestedConfigurations"></a><h3>Tested configurations</h3>
|
||||
<pre class="comment">vc2015 /EHsc
|
||||
vc2015 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
||||
vc2013 /EHsc
|
||||
vc2013 /EHsc /DBETTER_ENUMS_STRICT_CONVERSION
|
||||
vc2012 /EHsc
|
||||
vc2010 /EHsc
|
||||
vc2008 /EHsc
|
||||
clang++39 -std=c++11
|
||||
clang++39 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++39 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++39 -std=c++98
|
||||
clang++38 -std=c++11
|
||||
clang++38 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++38 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++38 -std=c++98
|
||||
clang++37 -std=c++11
|
||||
clang++37 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++37 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++37 -std=c++98
|
||||
clang++36 -std=c++11
|
||||
clang++36 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++36 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++36 -std=c++98
|
||||
clang++35 -std=c++11
|
||||
clang++35 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++35 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++35 -std=c++98
|
||||
clang++34 -std=c++11
|
||||
clang++34 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
clang++34 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
clang++34 -std=c++98
|
||||
clang++33 -std=c++98
|
||||
g++53 -std=c++11
|
||||
g++53 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++53 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++53 -std=c++98
|
||||
g++49 -std=c++11
|
||||
g++49 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++49 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++49 -std=c++98
|
||||
g++48 -std=c++11
|
||||
g++48 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++48 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++48 -std=c++98
|
||||
g++47 -std=c++11
|
||||
g++47 -std=c++11 -DBETTER_ENUMS_STRICT_CONVERSION
|
||||
g++47 -std=c++11 -DBETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
g++47 -std=c++98
|
||||
g++46 -std=c++98
|
||||
g++45 -std=c++98
|
||||
g++44 -std=c++98
|
||||
g++43 -std=c++98</pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
103
Contact.html
Normal file
103
Contact.html
Normal file
@ -0,0 +1,103 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Contact - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/Contact.html" />
|
||||
<meta name="description" content="Contact information for Better Enums bugs, issues, support, and feedback." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
<a href="Contact.html">Contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Contact</h2>
|
||||
<ul>
|
||||
<li>Send me an email: <a href="mailto:antonbachin@yahoo.com">antonbachin@yahoo.com</a>.</li>
|
||||
<li>Visit the <a href="https://github.com/aantron/better-enums">GitHub</a> project to open an issue or get a development
|
||||
version.</li>
|
||||
</ul>
|
||||
<p>I'm happy to hear any feedback. If you have any trouble using the library or
|
||||
parsing the documentation, please don't hesitate to let me know. I'd also be
|
||||
interested to hear about your use case, if you are willing to share :)</p>
|
||||
<p>And, if you find this library helpful, give it a star on GitHub to let me know
|
||||
you use it :)</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
301
DesignDecisionsFAQ.html
Normal file
301
DesignDecisionsFAQ.html
Normal file
@ -0,0 +1,301 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Design decisions FAQ - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/DesignDecisionsFAQ.html" />
|
||||
<meta name="description" content="Better Enums design decisions and tradeoffs." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Design decisions FAQ</h2>
|
||||
<p><span class="self">Better Enums</span> pushes at the edges of what is possible in standard <span class="cpp">C++</span>, and I've had to
|
||||
make some difficult decisions as a result. You can imagine the set of
|
||||
potential reflective enum implementations as a space, with axes such as "concise
|
||||
syntax," "uniform interface," "compilation speed," "run-time performance," and
|
||||
so on. As is typical in engineering, the constraints are such that as you move
|
||||
to extremes along one axis, you have to retreat along others — for
|
||||
example, some desirable aspects of concise syntax conflict with having a uniform
|
||||
interface, which is nonetheless good for teachability, and compile-time
|
||||
performance is, in some ways, at odds with run-time performance.</p>
|
||||
<p>So, there are many variations possible on <span class="self">Better Enums</span>, and, in fact, I have tried and
|
||||
maintained a few. This page describes how I chose the one that is published.
|
||||
The choices are debatable, but I am attempting to record the debate. Hopefully,
|
||||
this will either convince you that I have made a good choice, or, if you
|
||||
disagree, you will have a good starting point for discussion, or even for
|
||||
implementing an alternative.</p>
|
||||
<p>I am always looking for new arguments and approaches. If you have an idea,
|
||||
comment, criticism, please do <a href="Contact.html">let me know</a>.</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#WhyDoEnumMembersHaveUnderscores">Why do enum members have underscores?</a></li><li><a href="#WhyDoesBetterEnumsUseAMacroAtAll">Why does Better Enums use a macro at all?</a></li><li><a href="#WhyIsItNotPossibleToDeclareABetterEnumInsideAClass">Why is it not possible to declare a Better Enum inside a class?</a></li><li><a href="#ShouldBetterEnumsProvideEnum"objects"OrTraitsTypes">Should Better Enums provide enum "objects" or traits types?</a></li><li><a href="#WhyDoesBetterEnumsUseLinearScansForLookup">Why does Better Enums use linear scans for lookup?</a></li><li><a href="#WhyNotUseIndicesForTheRepresentation">Why not use indices for the representation?</a></li></ul></p>
|
||||
<a id="WhyDoEnumMembersHaveUnderscores"></a><h3>Why do enum members have underscores?</h3>
|
||||
<p>Enum members such as <code>_to_string</code> occupy the same scope as the names of
|
||||
constants declared by the user. I chose to prefix members with underscores to
|
||||
lessen the chances of collision. For example, take <code>_valid</code>, and suppose it was
|
||||
<code>valid</code> instead. That would make this enum impossible:</p>
|
||||
<pre><em>BETTER_ENUM(Status, char, valid, invalid)</em></pre><p>because the constant <code>Status::valid</code> would clash with the member
|
||||
<code>Status::valid</code>.</p>
|
||||
<p>Of course, users could try to declare constants with underscores as well, but I
|
||||
find it easier to ask users not to do that, rather than ask them to worry about
|
||||
a potentially growing set of reserved names, which they wouldn't fully know even
|
||||
for a single version of Better Enums, without frequently looking at the API
|
||||
documentation.</p>
|
||||
<p>Alternatives to this involve separating the namespaces occupied by members and
|
||||
constants. I don't think increasing nesting is an option, since nobody wants to
|
||||
write <code>Status::values::valid</code> or <code>Status::operations::valid</code>. I don't think
|
||||
moving constants out of <code>Status</code> is a good idea, since scoped constants is a
|
||||
feature of Better Enums, which is especially important for <span class="cpp">C++</span><span class="eleven">98</span> usage.</p>
|
||||
<p>This leaves the possibility of moving the operations performed by the members
|
||||
into traits types, i.e. something like <code>traits<Status>::valid</code>. That is an
|
||||
interesting option, and it has <a href="#Traits">its own section</a>. I have tried it, but
|
||||
the verbosity increase is much greater than the benefit of dropping underscores,
|
||||
so I chose not to do it.</p>
|
||||
<a id="WhyDoesBetterEnumsUseAMacroAtAll"></a><h3>Why does Better Enums use a macro at all?</h3>
|
||||
<p>Better Enums needs to turn the names of declared constants into strings, and I
|
||||
don't believe there is any way to do this in standard <span class="cpp">C++</span> except by using the
|
||||
preprocessor's macro parameter stringization operator (<code>#</code>). So, at the top
|
||||
level, Better Enums has to provide a macro. I am, however, trying to keep the
|
||||
user-facing macros to a minimum; in particular there is only one.</p>
|
||||
<p>I think that's the best that is possible. Furthermore, apart from the macro
|
||||
itself, the declaration looks very similar to a <span class="cpp">C++</span><span class="eleven">11</span> <code>enum</code> declaration, with
|
||||
an underlying type, comma-separated constant list, and the same support for
|
||||
initializers as built-in enums. So, I am trying to keep even this one macro out
|
||||
of the user's way. I wouldn't accept any change that involved turning the
|
||||
declaration into a preprocessor sequence or tuple, i.e. something like</p>
|
||||
<pre><em>BETTER_ENUM(Channel, int, (Red)(Green)((Blue)(5)))</em></pre><p>even if it promised extra capabilities.</p>
|
||||
<p>Better Enums uses additional macros internally, for two main purposes: to do the
|
||||
actual work of stringizing the declared constants and assembling them into
|
||||
arrays, and to configure itself by detecting which compiler it is running on.</p>
|
||||
<p>I am not a fan of gratuitous macros, but in these cases they are unavoidable,
|
||||
and, indeed, I am grateful for the stringization operator.</p>
|
||||
<p><a id="NoEnumInsideClass"></a></p>
|
||||
<a id="WhyIsItNotPossibleToDeclareABetterEnumInsideAClass"></a><h3>Why is it not possible to declare a Better Enum inside a class?</h3>
|
||||
<p>This is due to an interaction between linkage and <code>constexpr</code>.</p>
|
||||
<ol>
|
||||
<li><p>Better Enums is a header-only library that declares arrays with static
|
||||
storage, such as the array of constant names for each declared enum. Such
|
||||
arrays can be declared in namespace scope, in class scope, or in function
|
||||
scope, but they also need to be defined somewhere.</p>
|
||||
<p>If <code>BETTER_ENUM</code> is to be usable in both namespace and class scope, it
|
||||
already can't assume that it can declare arrays in namespace scope, since if
|
||||
<code>BETTER_ENUM</code> is used in a class, its entire expansion will be enclosed in
|
||||
the declaration of that class.</p>
|
||||
<p>That leaves class scope and function scope. If the arrays are declared in
|
||||
class scope, there needs to be a separate definition of them in some
|
||||
translation unit. This is too burdensome for the user, because the separate
|
||||
definition would involve repetition of the constants in the macro parameter
|
||||
list, creating exactly the type of maintenance problem that Better Enums is
|
||||
trying to eliminate.</p>
|
||||
<p>Function scope is the only viable option remaining after considering linkage
|
||||
constraints. Each array can be wrapped in a static function, which has a
|
||||
static local variable, which is initialized with the array. The functions can
|
||||
be called to get references to the arrays.</p>
|
||||
<p>However....</p>
|
||||
</li>
|
||||
<li><p>These arrays need to be accessible to <code>constexpr</code> code in <span class="cpp">C++</span><span class="eleven">11</span>, and
|
||||
<code>constexpr</code> functions are not allowed to have static local variables.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Ironically, this seems like one place where <span class="cpp">C++</span><span class="eleven">98</span> is more "flexible," but only
|
||||
for the reason that compile-time usage of Better Enums is not supported in
|
||||
<span class="cpp">C++</span><span class="eleven">98</span>.</p>
|
||||
<p><a id="Traits"></a></p>
|
||||
<a id="ShouldBetterEnumsProvideEnum"objects"OrTraitsTypes"></a><h3>Should Better Enums provide enum "objects" or traits types?</h3>
|
||||
<p>A Better Enum value is an "object," whose memory representation is the same as
|
||||
its underlying type. For example,</p>
|
||||
<pre><em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em></pre><p>expands to something like</p>
|
||||
<pre><em>struct Channel {
|
||||
enum _enumerated : int { Red, Green, Blue };
|
||||
int _value;</em>
|
||||
// Strings array, _to_string, _from_string, etc.
|
||||
<em>};</em></pre><hr>
|
||||
<p>There is an alternative interpretation, in which the Better Enums library
|
||||
generates enum traits instead, i.e. the generated arrays and members sit
|
||||
alongside built-in enums instead of wrapping them:</p>
|
||||
<pre><em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em></pre><p>generates</p>
|
||||
<pre><em>enum class Channel : int { Red, Green, Blue };</em>
|
||||
|
||||
<em>template <>
|
||||
struct ::better_enums::traits<Channel> {
|
||||
using _enumerated = Channel;</em>
|
||||
// Strings array, to_string, from_string, etc.
|
||||
<em>};</em></pre><hr>
|
||||
<p>There are a number of advantages to the traits approach.</p>
|
||||
<ul>
|
||||
<li>The underscore prefixes can be dropped from member names, since they no longer
|
||||
share a namespace with user-declared constants.</li>
|
||||
<li>The interface, at first glance, becomes more uniform, since now every member
|
||||
is a static member of the traits type. Without traits, <code>_to_string</code> is a
|
||||
non-static member, while <code>_from_string</code> is a static member.</li>
|
||||
<li><code>Channel</code> is one of the language's own enum types, instead of some mystery
|
||||
type provided by Better Enums. This may make it easier to understand. It also
|
||||
eliminates the problem with different syntaxes for <code>switch</code> statements
|
||||
described <a href="OptInFeatures.html#StrictConversions">here</a>.</li>
|
||||
</ul>
|
||||
<p>However, it also introduces some difficulties.</p>
|
||||
<ul>
|
||||
<li>The syntax is more verbose, since everything becomes a member of the traits
|
||||
type. For example, instead of <code>Channel::_from_string()</code>, you get
|
||||
<code>better_enums::traits<Channel>::from_string()</code>. The underscore may be
|
||||
unpleasant, but so far I have preferred the underscore to boilerplate.</li>
|
||||
<li><p>The uniform interface ends up getting wrapped behind functions anyway, for the
|
||||
sake of type inference. For example, the "naked" <code>to_string</code> function is
|
||||
called as <code>better_enums::traits<Channel>::to_string(channel)</code>, which is
|
||||
redundant, because the compiler could infer the type parameter <code>Channel</code> if it
|
||||
was the parameter of the function instead of the traits type. So, the obvious
|
||||
thing is to define such a wrapper function, which can then be called as
|
||||
<code>better_enums::to_string(channel)</code>. No such function can be easily defined for
|
||||
<code>from_string</code> and other <code>from_*</code> functions, however, because the type
|
||||
parameters can't be inferred from arguments. So, the signatures of <code>to_*</code> and
|
||||
<code>from_*</code> functions again effectively diverge, negating this advantage of
|
||||
traits. The closest I can get with wrappers is
|
||||
<code>better_enums::from_string<Channel></code>, which has the same signature only in the
|
||||
formal sense, i.e. modulo the difference in type inference.</p>
|
||||
<p>I actually think there is a way to infer the type parameter from the return
|
||||
type, similar to how it is done <a href="demo/SpecialValues.html">here</a>, but that will not be suitable
|
||||
for all contexts, and the user may be surprised by ambiguous resolution error
|
||||
messages when it is not.</p>
|
||||
</li>
|
||||
<li>Scoped constants are lost for <span class="cpp">C++</span><span class="eleven">98</span> unless Better Enums again wraps them in a
|
||||
generated type, though it will be more lightweight than a full Better Enum of
|
||||
the non-traits approach.</li>
|
||||
<li>Traits types must be specialized in either the same namespace scope they are
|
||||
declared in, or in an enclosing scope. This makes it impossible to declare an
|
||||
enum and specialize traits for it in a user's custom namespace.</li>
|
||||
</ul>
|
||||
<p>Despite the disadvantages listed just above, I consider the traits approach
|
||||
interesting — it's a close call. There is an
|
||||
<a href="https://github.com/aantron/better-enums/tree/traits">out-of-date branch</a> containing a traits version of Better Enums.
|
||||
You can see some of the usage in its <a href="https://github.com/aantron/better-enums/tree/traits/samples">samples</a> directory. I may
|
||||
update it from time to time, especially if there is interest.</p>
|
||||
<a id="WhyDoesBetterEnumsUseLinearScansForLookup"></a><h3>Why does Better Enums use linear scans for lookup?</h3>
|
||||
<p>It seems that Better Enums needs to use the same algorithms at compile time as
|
||||
at run time, because I have not found a way (and doubt there is one) to
|
||||
determine, during the execution of a <code>constexpr</code> function, whether it is
|
||||
executing at compile time or at run time. So, whatever data structures I use to
|
||||
accelerate lookup, I have to generate them at compile time, to be available as
|
||||
early as possible.</p>
|
||||
<p>I tried to generate various data structures at compile time, but so far,
|
||||
generation has been too slow. The fastest algorithm so far, a compile-time merge
|
||||
sort based on template parameter packs, took over 100ms to run on the constant
|
||||
set of a large enum. I would have to run three of these per enum — for the
|
||||
constants, for the names, and for the names with case-insensitive comparison.
|
||||
This results in a 300ms slowdown per enum, which is not acceptable, given that
|
||||
on my system the same compiler takes 370ms to process <code>iostream</code>, and less than
|
||||
10ms to process an enum without acceleration data structures. Declaring five
|
||||
large enums with accelerated lookup would take 1.5 seconds of compilation time.
|
||||
This doesn't scale to large projects with many translation units.</p>
|
||||
<p>I am continuing to look for faster algorithms or better approaches, so faster
|
||||
lookup may be coming to Better Enums in the future.</p>
|
||||
<p>So far, I have tried Boost.MPL sort, Eric Niebler's Meta sort, my own selection
|
||||
sort based on <code>constexpr</code>, and an insertion and merge sort based on parameter
|
||||
packs. I cannot use (Boost?).Hana sort, because that requires <span class="cpp">C++</span><span class="eleven">14</span>. I am also
|
||||
considering various hash table-like data structures, and providing two sets of
|
||||
interfaces for compile-time and run-time usage, which is something I would
|
||||
really rather not have to do. The latter option would be worth considering,
|
||||
however, if I measured a significant improvement in running time from better
|
||||
data structures — something I haven't gotten to yet because there doesn't
|
||||
seem to be a data structure to measure that is not disqualified by the speed of
|
||||
generation.</p>
|
||||
<a id="WhyNotUseIndicesForTheRepresentation"></a><h3>Why not use indices for the representation?</h3>
|
||||
<p>Representing Better Enum values by their indices in the declaration list seems
|
||||
like a tempting solution for the problem of having multiple constants with the
|
||||
same numeric value. It also speeds up some operations. For example, if a Better
|
||||
Enum is simply an index, then getting its string representation is simply
|
||||
indexing an array, rather than some kind of data structure lookup.</p>
|
||||
<pre>// Representations 0, 1, 2, 3 instead of 1, 2, 3, 1.
|
||||
<em>BETTER_ENUM(Kind, int, A = 1, B, C, D = A)</em></pre><p>Choosing this approach has serious drawbacks.</p>
|
||||
<ul>
|
||||
<li>The data structure lookup has simply been moved to another place. It now takes
|
||||
time to convert from a literal <code>Kind::D</code> to a Better Enum.</li>
|
||||
<li>It is still impossible to disambiguate between the literals <code>Kind::D</code> and
|
||||
<code>Kind::A</code> (1 and 1). Only the Better Enums objects of type <code>Kind</code> that
|
||||
represent <code>D</code> and <code>A</code> are different from each other (0 and 3). This is not
|
||||
only a technical problem, but is also quite unintuitive.</li>
|
||||
<li>Treating a Better Enum represented by an index as untyped memory produces
|
||||
surprising results. This makes Better Enums much less useful with functions
|
||||
such as <code>fwrite</code>. Worse, Better Enums become sensitive to declaration order
|
||||
even when initializers are given explicitly. Using indices for the
|
||||
representation makes it difficult to maintain compatibility with external
|
||||
protocols and file formats.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
148
ExtendingLimits.html
Normal file
148
ExtendingLimits.html
Normal file
@ -0,0 +1,148 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Extending limits - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/ExtendingLimits.html" />
|
||||
<meta name="description" content="How to extend limits imposed by internal macros in Better Enums." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Extending limits</h2>
|
||||
<p>The <code>BETTER_ENUM</code> macro makes heavy use of the preprocessor, and some of the
|
||||
internal macros have size limits. There are two: on the number of constants you
|
||||
can declare, and on the maximum length of a constant name under very specific
|
||||
conditions. If you run into either one, you can extend the limit by following
|
||||
the instructions on this page.</p>
|
||||
<p>The second limit, on the maximum length of a constant name, applies only when
|
||||
you are compiling an enum in
|
||||
<a href="OptInFeatures.html#CompileTimeNameTrimming">"full" <code>constexpr</code></a> mode
|
||||
<em>and</em> the constant has an initializer. Otherwise, your constants can have names
|
||||
of arbitrary length.</p>
|
||||
<p>The default limits are 64 constants in an enum and 23 characters for initialized
|
||||
constants of full-<code>constexpr</code> enums. To extend:</p>
|
||||
<ol>
|
||||
<li>Pick your desired limits. I will use 512 constants and 63 characters as an
|
||||
example. Add 1 to the number of characters to account for the null
|
||||
terminator — our numbers are now 512 and 64.</li>
|
||||
<li>Get <code>make_macros.py</code> from your copy of the full Better Enums distribution
|
||||
or from <a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/script/make_macros.py" download>GitHub</a>.</li>
|
||||
<li>You will run this script to generate a header file containing some
|
||||
replacement macros for <code>enum.h</code> to use. Pick a name for this file and a
|
||||
location somewhere in your include path. I will assume that this file is
|
||||
<code>common/enum_macros.h</code> in your project.</li>
|
||||
<li>Run <code>python make_macros.py 512 64 > common/enum_macros.h</code>.</li>
|
||||
<li><p>Define <code>BETTER_ENUMS_MACRO_FILE <common/enum_macros.h></code> before including
|
||||
<code>enum.h</code>. This is typically done by supplying extra flags to the compiler
|
||||
on the command line:</p>
|
||||
<ul>
|
||||
<li>For g++ and clang++, <code>-DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'</code></li>
|
||||
<li>For VC++, <code>\DBETTER_ENUMS_MACRO_FILE='<common/enum_macros.h>'</code></li>
|
||||
<li>With CMake, you may need something like
|
||||
<code>add_definitions(-DBETTER_ENUMS_MACRO_FILE="${CMAKE_SOURCE_DIR}/src/enum-macros.h")</code></li>
|
||||
</ul>
|
||||
<p>You can also create a new header file that defines this macro, and then
|
||||
includes <code>enum.h</code>. Then, include your new file everywhere where you would
|
||||
otherwise include <code>enum.h</code>:</p>
|
||||
<pre class="comment"><em>#pragma once
|
||||
|
||||
#define BETTER_ENUMS_MACRO_FILE <common/enum_macros.h>
|
||||
#include <enum.h></em></pre></li>
|
||||
<li><p>Enjoy the looser limits. Just watch out — increasing the second
|
||||
number can really slow down compilation of full-<code>constexpr</code> enums.</p>
|
||||
</li>
|
||||
<li>You don't need <code>make_macros.py</code> anymore. It's not part of your build
|
||||
process and you can delete it.</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<p>I am paying attention to feedback, so if more than a few users say that the
|
||||
default limit of 64 constants is too low, I will increase it to simplify
|
||||
everyone's command line. The current choice of 64 is basically an arbitrary
|
||||
guess, loosely informed by the following two facts about macro parameter limits:</p>
|
||||
<ul>
|
||||
<li>The default limit in Boost.Preprocessor is 64. Though Better Enums does not
|
||||
use Boost, I took this number as a guideline.</li>
|
||||
<li>The next power of two, 128, is more than <a href="https://msdn.microsoft.com/en-us/library/ft39hh4x.aspx">the number Visual C++ supports</a>
|
||||
(127).</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
183
GeneralUnderlyingTypes.html
Normal file
183
GeneralUnderlyingTypes.html
Normal file
@ -0,0 +1,183 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>General underlying types - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/GeneralUnderlyingTypes.html" />
|
||||
<meta name="description" content=""Using Better Enums with non-integral underlying types."" />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
<a href="Contact.html">Contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.10.1</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>General underlying types</h2>
|
||||
<p>The underlying type of a Better Enum doesn't have to be an integral type. It can
|
||||
be any literal type <code>T</code>, as long as you provide a <code>constexpr</code> two-way mapping
|
||||
between <code>T</code> and an integral type of your choosing. It also works in <span class="cpp">C++</span><span class="eleven">98</span>,
|
||||
though, of course, <code>T</code> doesn't have to be literal and the mapping doesn't have
|
||||
to be <code>constexpr</code> — everything will be done by Better Enums at run time.</p>
|
||||
<p>Doing this enables the following usage:</p>
|
||||
<pre>// The type. A color triplet.
|
||||
<em>struct html_color {
|
||||
uint8_t r, g, b;
|
||||
|
||||
constexpr html_color(uint8_t _r, uint8_t g, uint8_t b) :
|
||||
r(_r), g(_g), b(_b) { }
|
||||
};</em>
|
||||
|
||||
|
||||
|
||||
// The enum.
|
||||
<em>ENUM(Color, html_color,
|
||||
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954)</em>
|
||||
|
||||
|
||||
|
||||
// The usage.
|
||||
<em>Color c = Color::darksalmon;
|
||||
|
||||
std::cout << "Red component: " << c->r << std::endl;
|
||||
|
||||
switch (c) {
|
||||
case Color::darksalmon: // ...
|
||||
case Color::purplemimosa: // ...
|
||||
case Color::slimegreen: // ...
|
||||
}</em></pre><p>As you can see, you can have an enumerated set of any literal type, and safely
|
||||
use the values in <code>switch</code>, with the compiler checking exhaustiveness. You can
|
||||
also access the type's members using the <code>enum->underlying_member</code> syntax.</p>
|
||||
<p>You do have to supply the mapping to an integral type, however. One option is:</p>
|
||||
<pre>// The mapping. It just stuffs bits.
|
||||
<em>template <>
|
||||
struct ::better_enums::underlying_traits<html_color> {
|
||||
using integral_representation = unsigned int;
|
||||
|
||||
constexpr static html_color from_integral(unsigned int i)
|
||||
{ return html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
|
||||
|
||||
constexpr static unsigned int to_integral(html_color c)
|
||||
{ return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
|
||||
};</em></pre><a id="UsingConstructorsInInitializers"></a><h3>Using constructors in initializers</h3>
|
||||
<p>The declaration above used only numeric initializers. It is possible to use the
|
||||
type's own constructors, provided the type has a <code>constexpr</code> conversion to your
|
||||
chosen integral type:</p>
|
||||
<pre>// The type.
|
||||
<em>struct html_color {
|
||||
uint8_t r, g, b;
|
||||
|
||||
constexpr html_color(uint8_t _r, uint8_t g, uint8_t b) :
|
||||
r(_r), g(_g), b(_b) { }
|
||||
|
||||
</em>// This is new:<em>
|
||||
constexpr operator unsigned int() const
|
||||
{ return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
|
||||
};</em>
|
||||
|
||||
// The enum.
|
||||
<em>ENUM(Color, html_color,
|
||||
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954,
|
||||
celeste = html_color(0x50, 0xeb, 0xec))</em></pre><p>This is not possible at all in <span class="cpp">C++</span><span class="eleven">98</span>, however.</p>
|
||||
<a id="LettingTheCompilerEnumerateYourLiteralType"></a><h3>Letting the compiler enumerate your literal type</h3>
|
||||
<p>You don't have to use initializers. For example, as long as your example type
|
||||
<code>file_descriptor</code> knows how to deal with the values, you can have the compiler
|
||||
generate them in sequence:</p>
|
||||
<pre><em>ENUM(FD, file_descriptor, STDIN, STDOUT, STDERR, SomePipeYourDaemonHas, ...)</em></pre><p>SAMPLE</p>
|
||||
<p>You can see the code "in action" in the <a href="https://github.com/aantron/better-enums/blob/master/test/cxxtest/underlying.h">test case</a>. Be aware that it's
|
||||
not very "nice," because it uses conditional compilation to run under multiple
|
||||
compilers. I haven't written a clean sample or documentation yet simply because
|
||||
this feature is in a very early stage of development.</p>
|
||||
<a id="Discussion"></a><h3>Discussion</h3>
|
||||
<p>This feature is still semi-experimental, though I expect it to remain stable,
|
||||
except perhaps that I will make it possible to infer the type
|
||||
<code>integral_representation</code>.</p>
|
||||
<p>Any opinions are welcome.</p>
|
||||
<ul>
|
||||
<li>The main reason Better Enums needs you to supply and explicit mapping is
|
||||
because it can't just get the "bits" of objects of underlying type in
|
||||
<code>constexpr</code> code. Both <code>reinterpret_cast</code> and union abuse seem to be forbidden
|
||||
in <code>constexpr</code> functions.</li>
|
||||
<li>There is currently no way to have two different integral representaitons for
|
||||
the same underlying type in different enums. I don't think that's a major use
|
||||
case at this point, however.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015 Anton Bachin. Released under the BSD 2-clause license.
|
||||
See
|
||||
<a href="https://github.com/aantron/better-enums/blob/master/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.10.1.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
165
OptInFeatures.html
Normal file
165
OptInFeatures.html
Normal file
@ -0,0 +1,165 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Opt-in features - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/OptInFeatures.html" />
|
||||
<meta name="description" content="Optional Better Enums features, disabled by default for
|
||||
performance or compatibility reasons." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Opt-in features</h2>
|
||||
<p>Better Enums has two opt-in features. They are both "good," but they either hurt
|
||||
compilation time or break compatibility with <span class="cpp">C++</span><span class="eleven">98</span>, so they are disabled by
|
||||
default. Read this page if you want to enable them.</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#DefaultConstructors">Default constructors</a></li><li><a href="#CompileTimeNameTrimming">Compile-time name trimming</a></li><li><a href="#StrictConversions">Strict conversions</a></li><li><a href="#InjectingTokens">Injecting tokens</a></li></ul></p>
|
||||
<a id="DefaultConstructors"></a><h3>Default constructors</h3>
|
||||
<p>Better Enums generate with inaccessible (private or deleted) default
|
||||
constructors. This is meant to help control where in your program Better Enums
|
||||
values are introduced, and thus ensure that only valid, properly initialized
|
||||
enum values are ever created.</p>
|
||||
<p>If you want Better Enums to have a default constructor, you can do something
|
||||
like the following:</p>
|
||||
<pre><em>#define</em> <em>BETTER_ENUMS_DEFAULT_CONSTRUCTOR</em>(<em>Enum</em>) \
|
||||
<em>public</em>: \
|
||||
<em>Enum()</em> = <em>default</em>;
|
||||
|
||||
<em>#include</em> <<em>enum.h</em>></pre><p>You can put this in its own header file, and include that header file instead of
|
||||
including <code>enum.h</code> directly.</p>
|
||||
<a id="CompileTimeNameTrimming"></a><h3>Compile-time name trimming</h3>
|
||||
<p>This makes <code>_to_string</code> and <code>_names</code> <code>constexpr</code>, i.e. "full" <code>constexpr</code> mode.
|
||||
To enable this for all enums, define <code>BETTER_ENUMS_CONSTEXPR_TO_STRING</code> before
|
||||
including <code>enum.h</code>. Typically, you would pass an option to your compiler to do
|
||||
this.</p>
|
||||
<p>You can also enable this feature for individual enums instead, by declaring them
|
||||
using the alternative <code>SLOW_ENUM</code> macro.</p>
|
||||
<p>The feature is disabled because it increases compilation times by a factor of
|
||||
about 4. Compilation is still relatively fast — you need about a dozen
|
||||
slow enums to get the same penalty as including <code>iostream</code> — but it is
|
||||
a steep penalty nonetheless. I don't think most people need this feature most of
|
||||
the time, so it's too high a price to pay. If I improve compilation times to the
|
||||
point where compile-time name trimming can be the default, I will simply
|
||||
redefine <code>SLOW_ENUM</code> as <code>BETTER_ENUM</code> and deprecate it, so your code will still
|
||||
work.</p>
|
||||
<a id="StrictConversions"></a><h3>Strict conversions</h3>
|
||||
<p>This disables implicit conversions to underlying integral types. At the moment,
|
||||
you can only enable this globally for all enums, by defining
|
||||
<code>BETTER_ENUMS_STRICT_CONVERSION</code> before including <code>enum.h</code>.</p>
|
||||
<p>The reason Better Enums have implicit conversions to integral types in the first
|
||||
place is that in <span class="cpp">C++</span><span class="eleven">98</span>, Better Enums have to be implicitly convertible to their
|
||||
member <a href="ApiReference.html#Typedef_enumerated"><code>_enumerated</code></a> types to
|
||||
be <a href="tutorial/SafeSwitch.html">usable</a> in <code>switch</code> statements. It is
|
||||
possible to avoid this in <span class="cpp">C++</span><span class="eleven">11</span> and convert to <code>enum class</code> types instead, but
|
||||
at the cost of breaking interface compatibility with <span class="cpp">C++</span><span class="eleven">98</span>.</p>
|
||||
<ul>
|
||||
<li>The "weaker" incompatibility is that you could write a bunch of <span class="cpp">C++</span><span class="eleven">98</span> code
|
||||
that relies on implicit integer conversions, and then try to switch to
|
||||
<span class="cpp">C++</span><span class="eleven">11</span>. The code would then fail to compile. An example where implicit
|
||||
conversions are an "advantage" is when using Better Enums as arguments to
|
||||
the methods of <code>std::bitset</code>. I could have ignored this problem by declaring
|
||||
usage of implicit integer conversions unsupported, but in light of the next
|
||||
issue, I decided not to do that.</li>
|
||||
<li>The "stronger" incompatibility is a difference in how <code>switch</code> cases must be
|
||||
written. The syntaxes for the two variants, implicitly-converting and
|
||||
strict, are mutually exclusive. They differ by a <code>+</code> character.</li>
|
||||
</ul>
|
||||
<p>Here they are:</p>
|
||||
<pre>// Default variant
|
||||
<em>switch</em> (<em>channel</em>) {
|
||||
case Channel::Red: break;
|
||||
case Channel::Green: break;
|
||||
case Channel::Blue: break;
|
||||
}
|
||||
|
||||
// Strict variant
|
||||
<em>switch</em> (<em>channel</em>) {
|
||||
case <em>+</em>Channel::Red: break;
|
||||
case <em>+</em>Channel::Green: break;
|
||||
case <em>+</em>Channel::Blue: break;
|
||||
}</pre><a id="InjectingTokens"></a><h3>Injecting tokens</h3>
|
||||
<p>You can define <code>BETTER_ENUMS_CLASS_ATTRIBUTE</code> before declaring a Better Enum, to
|
||||
inject tokens into the class declaration. For example, in</p>
|
||||
<pre>#define <em>BETTER_ENUMS_CLASS_ATTRIBUTE</em> <em>__attribute__(foo)</em>
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)</pre><p>The resulting enum declaration will begin with</p>
|
||||
<pre>class <em>__attribute__(foo)</em> <em>Channel</em> {</pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
134
Performance.html
Normal file
134
Performance.html
Normal file
@ -0,0 +1,134 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Performance - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/Performance.html" />
|
||||
<meta name="description" content="Better Enums compilation speed and performance testing results." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<h2>Performance</h2>
|
||||
<p>A basic performance test is run on
|
||||
<a href="CompilerSupport.html#TestedConfigurations">every compiler tested</a>. It
|
||||
doesn't try to be very accurate — it just stress-tests the compiler once
|
||||
to get a rough idea of how long it takes to compile Better Enums.</p>
|
||||
<p>The files compared in the test are as follows:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/aantron/better-enums/blob/0.11.3/test/performance/4-declare_enums.cc">One file</a> includes
|
||||
<code>enum.h</code> and declares 647 constants across 36 Better Enums.</li>
|
||||
<li>The <a href="https://github.com/aantron/better-enums/blob/0.11.3/test/performance/5-iostream.cc">other file</a> <em>only</em>
|
||||
includes <code>iostream</code> and does nothing with it.</li>
|
||||
</ul>
|
||||
<p>The argument is that if compiling a bunch of Better Enums is faster, or about as
|
||||
fast as, including a single standard header such as <code>iostream</code>, then Better
|
||||
Enums is fast enough for general use.</p>
|
||||
<p>Results are given for select compilers and
|
||||
<a href="CompilerSupport.html#CompileTimeReflectionConfigurations">configurations</a>
|
||||
as ratios of how long it took to compile the Better Enums file to how long it
|
||||
took to compile the <code>iostream</code> file. The less the ratio, the better. Ratios less
|
||||
than 1 mean the enums compiled faster, and ratios greater than 1 mean <code>iostream</code>
|
||||
compiled faster.</p>
|
||||
<ul>
|
||||
<li>clang 3.6, fast <code>constexpr</code>: 0.66</li>
|
||||
<li>clang 3.6, full <code>constexpr</code>: 2.25</li>
|
||||
<li>gcc 5.1, fast <code>constexpr</code>: 1.58</li>
|
||||
<li>gcc 5.1, full <code>constexpr</code>: 4.23</li>
|
||||
<li>VC2015RC, <span class="cpp">C++</span><span class="eleven">98</span>: 1.18</li>
|
||||
</ul>
|
||||
<p>The time to merely include <code>enum.h</code> vary widely by compiler, with clang being
|
||||
by far the fastest. The ratios to <code>iostream</code> are given below.</p>
|
||||
<ul>
|
||||
<li>clang 3.6: 0.15</li>
|
||||
<li>gcc 5.1: 0.77</li>
|
||||
<li>VC2015RC: 0.82</li>
|
||||
</ul>
|
||||
<p>On my test machines, clang processed the file in 40ms, gcc took 230ms, and
|
||||
VC2015 took 820ms. The first two are comparable to each other, but VC2015 runs
|
||||
on a different machine.</p>
|
||||
<hr>
|
||||
<p>In general, I am very sensitive to performance. Better Enums was originally
|
||||
developed in the context of a commercial project where slow running times <em>and</em>
|
||||
slow compilation times were unacceptable. I am continuing to develop it in this
|
||||
spirit.</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
595
better-enums.css
Normal file
595
better-enums.css
Normal file
@ -0,0 +1,595 @@
|
||||
body {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
pre, code, samp, h4, .contents ul {
|
||||
font-family:
|
||||
Consolas, "Liberation Mono", Menlo, "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
h1, .splash-text .self, nav .self {
|
||||
font-family: Georgia, Times, "Times New Roman", serif;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #477093;
|
||||
padding: 1.5em 20px;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 78%;
|
||||
max-width: 84ex;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
pre em {
|
||||
font-style: normal;
|
||||
text-shadow: 0 -1px grey;
|
||||
color: white;
|
||||
}
|
||||
|
||||
pre.comment {
|
||||
background-color: #EEF4F9;
|
||||
color: #888;
|
||||
border: 1px dashed #477093;
|
||||
}
|
||||
|
||||
pre.comment em {
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
code, samp {
|
||||
background-color: #EEF4F9;
|
||||
padding: 1px 3px;
|
||||
border-radius: 3px;
|
||||
font-size: 78%;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: 150px;
|
||||
margin-right: 150px;
|
||||
}
|
||||
|
||||
.main .container > * {
|
||||
max-width: 41em;
|
||||
}
|
||||
|
||||
.index .main .container > * {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.main .container > .contents {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 1100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
.container {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
border-bottom: 1px solid #68a;
|
||||
color: white;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
nav, .spacer {
|
||||
padding: 0.75em 0;
|
||||
font-size: 14px;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
nav > * > span {
|
||||
float: right;
|
||||
opacity: 0.9;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
nav .self {
|
||||
font-size: 16px;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
nav a.first {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
nav {
|
||||
position: initial;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #4C6F8C;
|
||||
background: linear-gradient(#395E7E, #4A79A0);
|
||||
color: white;
|
||||
padding: 50px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 60px;
|
||||
font-weight: normal;
|
||||
text-shadow: -2px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
header section {
|
||||
float: left;
|
||||
}
|
||||
|
||||
header section.buttons, header section.notes {
|
||||
float: right;
|
||||
margin-top: 1.75em;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
header section.notes {
|
||||
max-width: 20em;
|
||||
font-size: 75%;
|
||||
margin-right: 10px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
header section.notes p {
|
||||
margin: 0.35em 0.35em;
|
||||
}
|
||||
|
||||
header section.notes code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
header h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 100;
|
||||
position: relative;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
header h3 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
position: relative;
|
||||
left: 4px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.buttons a {
|
||||
display: block;
|
||||
background-color: rgba(255, 255, 255, 0.2) !important;
|
||||
width: 10em;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
padding: 0.25em 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.buttons a:hover {
|
||||
background-color: white !important;
|
||||
color: #395E7E;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
header .notes {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header .buttons {
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 660px) {
|
||||
header .buttons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 2em;
|
||||
font-size: 36px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 14px;
|
||||
margin-top: 100px;
|
||||
margin-bottom: 20px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
/*background-color: red;*/
|
||||
}
|
||||
|
||||
a[href=""] {
|
||||
color: white !important;
|
||||
/*background-color: red !important;*/
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
header a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.main a[href], footer a[href] {
|
||||
background-color: #edd;
|
||||
color: #844;
|
||||
letter-spacing: -0.5px;
|
||||
padding: 0 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
header a[href], nav a[href] {
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
letter-spacing: inherit;
|
||||
}
|
||||
|
||||
a[href] code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
span.cpp, span.cc {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
span.eleven {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
span#note:target {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.pane {
|
||||
float: left;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.hack {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.pane.left > * {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.pane.right > * {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
font-size: 30px;
|
||||
margin-top: 2em;
|
||||
color: black;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
h3.contents {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.pane pre {
|
||||
font-size: 14px;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
header {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header .container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.back {
|
||||
position: absolute;
|
||||
bottom: -0.35em;
|
||||
left: -40px;
|
||||
font-size: 288px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 20px;
|
||||
opacity: 0.1;
|
||||
text-shadow: -20px 20px #444;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.panes {
|
||||
clear: both;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.tutorial-footer {
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
.tutorial-footer .next {
|
||||
font-weight: 100;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.tutorial-footer .next a[href] {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.blurbs {
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.blurbs > li {
|
||||
float: left;
|
||||
min-height: 5em;
|
||||
}
|
||||
|
||||
@media (min-width: 1076px) {
|
||||
.blurbs > li {
|
||||
width: 28%;
|
||||
margin-right: 4%;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-three {
|
||||
clear: both;
|
||||
margin-left: 2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1075px) {
|
||||
.blurbs > li {
|
||||
width: 45%;
|
||||
margin-right: 4%;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-two {
|
||||
clear: both;
|
||||
margin-left: 2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.blurbs > li {
|
||||
float: none;
|
||||
width: 100%;
|
||||
min-height: 3em;
|
||||
}
|
||||
|
||||
.blurbs > li.zero-mod-two {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.blurbs strong {
|
||||
font-weight: inherit;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.blurbs em {
|
||||
display: block;
|
||||
margin-bottom: 1em;
|
||||
font-size: 80%;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.act strong {
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.act strong code {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.resources > li {
|
||||
margin-bottom: 3.5em;
|
||||
}
|
||||
|
||||
.resources li ul, .resources li ol {
|
||||
margin-top: 1.5em;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.splash-text {
|
||||
padding-top: 1em;
|
||||
font-size: 150%;
|
||||
font-weight: normal;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.splash-text em {
|
||||
border-bottom: 1px solid #888;
|
||||
}
|
||||
|
||||
.splash-text .self {
|
||||
color: #777;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.splash {
|
||||
float: right;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.splash pre {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.splash pre.left {
|
||||
text-align: right;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
background-color: transparent;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.splash pre.right {
|
||||
text-align: left;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.splash {
|
||||
float: none;
|
||||
margin-left: -10%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.splash {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.splash pre.left {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a[id] {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: -25px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
margin-top: 3em;
|
||||
letter-spacing: -1px;
|
||||
color: #888;
|
||||
padding-top: 1em;
|
||||
white-space: nowrap;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
h4 em {
|
||||
color: #555;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.api ul.contents {
|
||||
-webkit-columns: 300px 3;
|
||||
-moz-columns: 300px 3;
|
||||
columns: 300px 3;
|
||||
}
|
||||
|
||||
.api ul.contents > li {
|
||||
-webkit-column-break-inside: avoid;
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
margin-top: 4em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h3.contents {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.index .main h3 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.api .contents ul {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.api .contents > li {
|
||||
margin-top: 0;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.buttons-bar {
|
||||
background-color: #f4f4f4;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.buttons-bar a img {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.buttons-bar iframe.gh-button {
|
||||
width: 95px;
|
||||
}
|
||||
|
||||
.buttons-bar .tweet-share,
|
||||
.buttons-bar .gh-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.index .buttons-bar .tweet-share,
|
||||
.index .buttons-bar .gh-button {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.buttons-bar iframe.gh-watch {
|
||||
width: 103px;
|
||||
}
|
||||
|
||||
.external {
|
||||
font-size: 75%;
|
||||
}
|
||||
154
demo/BitSets.html
Normal file
154
demo/BitSets.html
Normal file
@ -0,0 +1,154 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Bit sets - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/BitSets.html" />
|
||||
<meta name="description" content="Finding the maximum value of a Better Enum for use in declaring
|
||||
statically-sized bit set types." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This is an example of code you can write on top of Better Enums. It's a valid
|
||||
program — you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/103-bitset.cc">download</a> it and try it out. The
|
||||
program is also part of the test suite.
|
||||
</p>
|
||||
|
||||
<h2>Bit sets</h2>
|
||||
<p>If you want to use <code>std::bitset</code> or a similar library to have enums be keys into
|
||||
a bit set, you need to know the number of bits at compile time. You can easily
|
||||
automate this with Better Enums, even when constants are not declared in
|
||||
increasing order.</p>
|
||||
<hr>
|
||||
<p>We simply need to find the maximum value of any given enum type.</p>
|
||||
<pre>#include <bitset>
|
||||
#include <iostream>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
template <<em>typename Enum</em>>
|
||||
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||
max_loop<Enum>(accumulator, index + 1)</em>;
|
||||
}
|
||||
|
||||
template <<em>typename Enum</em>>
|
||||
constexpr <em>Enum max</em>()
|
||||
{
|
||||
return <em>max_loop<Enum>(Enum::_values()[0], 1)</em>;
|
||||
}</pre><p>And use that to declare a bit set template:</p>
|
||||
<pre>template <<em>typename Enum</em>>
|
||||
using <em>EnumSet</em> = <em>std::bitset</em><<em>max<Enum>()._to_integral()</em> + <em>1</em>>;</pre><p>Now, we can have bit sets that are wide enough to hold whatever range we
|
||||
declared. We just declare enums, and the numeric values of their constants will
|
||||
be bit indices. The rest is straightforward.</p>
|
||||
<pre>BETTER_ENUM(<em>EFLAGS</em>, int,
|
||||
<em>Carry</em>, <em>Parity</em> = 2, <em>Adjust</em> = 4, <em>Zero</em>, <em>Sign</em>, <em>Trap</em>, <em>Interrupt</em>, <em>Direction</em>,
|
||||
<em>Overflow</em>, <em>NestedTask</em> = 14, <em>Resume</em> = 16, <em>V8086</em>, <em>AlignmentCheck</em>,
|
||||
<em>CPUIDPresent</em> = 21)
|
||||
|
||||
int main()
|
||||
{
|
||||
<em>EnumSet</em><<em>EFLAGS</em>> eflags = <em>1 << EFLAGS::Carry</em> | <em>1 << EFLAGS::Zero</em>;
|
||||
|
||||
if (eflags.test(<em>EFLAGS::Carry</em>))
|
||||
eflags.set(<em>EFLAGS::Trap</em>);
|
||||
|
||||
std::cout << <em>eflags</em> << std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><hr>
|
||||
<p>If we want bit sets of fixed known width instead, we can use the code above to
|
||||
check that we haven't declared any bit indices out of range:</p>
|
||||
<pre class="comment">static_assert(max<EFLAGS>()._to_integral() < 32,
|
||||
"some bit indices are out of range");</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
156
demo/C++17Reflection.html
Normal file
156
demo/C++17Reflection.html
Normal file
@ -0,0 +1,156 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>C++17 reflection - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/C++17Reflection.html" />
|
||||
<meta name="description" content="Approximate implementation of N4428 enum reflection based on
|
||||
Better Enums." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
<a href="../Contact.html">Contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.10.1</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This page is an advanced demo showing the kind of code you can write on top of
|
||||
Better Enums. It's a valid program — you can
|
||||
<a href="https://github.com/aantron/better-enums/blob/master/example/105-c++17-reflection.cc">download</a> it and try it out. The program runs as part of
|
||||
the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>C++17 reflection</h2>
|
||||
<p>Better Enums can be used to approximately implement the enums portion of the
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf"><span class="cpp">C++</span><span class="eleven">17</span> reflection proposal N4428</a> in <span class="cpp">C++</span><span class="eleven">11</span>. The implementation is
|
||||
<em>approximate</em> in the following senses:</p>
|
||||
<ul>
|
||||
<li>It only applies to Better Enums, not built-in enums.</li>
|
||||
<li><code>enum_traits<E>::enumerators::get<I>::identifier</code> is a non-<code>constexpr</code>
|
||||
function rather than a <code>constexpr</code> variable. I could make it a <code>constexpr</code>
|
||||
variable as in the proposal, but that requires
|
||||
<a href="../OptInFeatures.html#CompileTimeNameTrimming">compile-time name trimming</a> to be enabled for the Better Enum
|
||||
on which <code>get</code> is used. Since that's an opt-in feature, I can't guarantee it.
|
||||
I preferred not to write feature-detection code, in order to keep the
|
||||
implementation simple.</li>
|
||||
<li>The return type of <code>identifier</code> is <code>const char*</code> instead of the proposed
|
||||
<code>std::string_literal</code>, because I don't have an implementation of the latter
|
||||
available. I'm also ignoring the requirements on encoding, and just taking
|
||||
whatever the preprocessor provides.</li>
|
||||
</ul>
|
||||
<p>With that out of the way, we can look at a simple example.</p>
|
||||
<hr>
|
||||
<p>The implementation is defined in <a href="https://github.com/aantron/better-enums/blob/master/extra/better-enums/n4428.h"><code>extra/better-enums/n4428.h</code></a>. Let's
|
||||
assume that <code>extra/</code> has been added as a directory to search for include files.</p>
|
||||
<pre>#include <iostream>
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
<em>#include</em> <<em>better-enums/n4428.h</em>></pre><hr>
|
||||
<p>Let's declare an enum:</p>
|
||||
<pre><em>ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)</pre><p>N4428 proposes three <code>constexpr</code> traits, of which we have two implemented
|
||||
exactly — that is, as <code>constexpr</code>:</p>
|
||||
<pre><em>constexpr std::size_t size</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>size</em>;
|
||||
|
||||
<em>constexpr Channel value_0</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>0</em>>::<em>value</em>;
|
||||
<em>constexpr Channel value_1</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>1</em>>::<em>value</em>;</pre><p>Let's check the results:</p>
|
||||
<pre>static_assert(<em>size</em> == <em>3</em>, "");
|
||||
|
||||
static_assert(<em>value_0</em> == +<em>Channel::Red</em>, "");
|
||||
static_assert(<em>value_1</em> == +<em>Channel::Green</em>, "");</pre><p>Finally, we can try using <code>identifier</code>:</p>
|
||||
<pre>int main()
|
||||
{
|
||||
std::cout
|
||||
<< <em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>2</em>>::<em>identifier</em>()
|
||||
<< std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><p>That prints <code>Blue</code>, as you would expect.</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015 Anton Bachin. Released under the BSD 2-clause license.
|
||||
See
|
||||
<a href="https://github.com/aantron/better-enums/blob/master/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.10.1.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
224
demo/C++17ReflectionProposal.html
Normal file
224
demo/C++17ReflectionProposal.html
Normal file
@ -0,0 +1,224 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>C++17 reflection proposal - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html" />
|
||||
<meta name="description" content="Approximate implementation of N4428 enum reflection based on
|
||||
Better Enums." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This is an example of code you can write on top of Better Enums. It's a valid
|
||||
program — you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/105-c++17-reflection.cc">download</a> it and try it out. The
|
||||
program is also part of the test suite.
|
||||
</p>
|
||||
|
||||
<h2>C++17 reflection proposal</h2>
|
||||
<p><em>You can try this demo <a href="http://melpon.org/wandbox/permlink/QelcwZNLi4gIx8Ux">live online</a>.</em></p>
|
||||
<p>Better Enums can be used to implement the enums portion of the
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf"><span class="cpp">C++</span><span class="eleven">17</span> reflection proposal N4428</a> in <span class="cpp">C++</span><span class="eleven">11</span>. N4428 proposes the
|
||||
following traits interface:</p>
|
||||
<pre class="comment"><em>namespace std {
|
||||
|
||||
template <typename E>
|
||||
struct enum_traits {
|
||||
struct enumerators {
|
||||
constexpr static size_t size;
|
||||
|
||||
template <size_t I>
|
||||
struct get {
|
||||
constexpr string_literal identifier;
|
||||
constexpr static E value;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}</em></pre><p>So, the basic usage would be:</p>
|
||||
<pre class="comment"><em>enum class Foo {A, B, C};
|
||||
|
||||
constexpr size_t size =
|
||||
std::enum_traits<Foo>::enumerators::size;
|
||||
|
||||
constexpr Foo value_0 =
|
||||
std::enum_traits<Foo>::enumerators::get<0>::value;
|
||||
|
||||
constexpr string_literal name_1 =
|
||||
std::enum_traits<Foo>::enumerators::get<1>::identifier;</em></pre><p>Resulting in the values <code>3</code>, <code>Foo::A</code>, and <code>"B"</code>, respectively.</p>
|
||||
<hr>
|
||||
<p>The interface is implemented in the optional header file
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/extra/better-enums/n4428.h"><code>extra/better-enums/n4428.h</code></a>. There is a necessary difference: the
|
||||
interface is only available for enums declared through the <code>BETTER_ENUM</code> macro.
|
||||
This is because the macro is what generates the information necessary for
|
||||
reflection.</p>
|
||||
<a id="Demo"></a><h3>Demo</h3>
|
||||
<p>So, with that out of the way, we can do a little test. Let's assume that
|
||||
<code>extra/</code> has been added as a directory to search for include files.</p>
|
||||
<pre>#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
<em>#include</em> <<em>better-enums/n4428.h</em>></pre><hr>
|
||||
<p>Let's declare an enum:</p>
|
||||
<pre><em>BETTER_ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)</pre><p>...and try N4428:</p>
|
||||
<pre>constexpr std::size_t <em>size</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>size</em>;
|
||||
|
||||
constexpr Channel <em>value_0</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>0</em>>::<em>value</em>;
|
||||
|
||||
constexpr Channel <em>value_1</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>1</em>>::<em>value</em>;
|
||||
|
||||
constexpr const char *<em>identifier_2</em> =
|
||||
<em>std</em>::<em>enum_traits</em><<em>Channel</em>>::<em>enumerators</em>::<em>get</em><<em>2</em>>::<em>identifier</em>;</pre><p>...and check the results:</p>
|
||||
<pre>static_assert(<em>size</em> == <em>3</em>, "");
|
||||
|
||||
static_assert(<em>value_0</em> == +<em>Channel::Red</em>, "");
|
||||
static_assert(<em>value_1</em> == +<em>Channel::Green</em>, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>identifier_2</em> << std::endl;
|
||||
return 0;
|
||||
}</pre><p>That prints <code>Blue</code>, as you would expect.</p>
|
||||
<a id="Quirk"></a><h3>Quirk</h3>
|
||||
<p>The reason for the <code>#define</code> in the code above is that there is one quirk:
|
||||
the interface above is available only for Better Enums for which
|
||||
<a href="../OptInFeatures.html#CompileTimeNameTrimming">compile-time name trimming</a> is enabled — those declared when
|
||||
<code>BETTER_ENUMS_CONSTEXPR_TO_STRING</code> was defined, or declared with the <code>SLOW_ENUM</code>
|
||||
variant of <code>BETTER_ENUM</code>. As mentioned on the linked page, the reason
|
||||
compile-time name trimming is not the default is that, while still pretty fast,
|
||||
it is four times slower than program-startup-time name trimming. The latter is
|
||||
the default.</p>
|
||||
<p>Despite the above, a variation on the interface is available for enums without
|
||||
compile-time name trimming:</p>
|
||||
<pre class="comment"><em>namespace std {
|
||||
|
||||
template <typename E>
|
||||
struct enum_traits {
|
||||
struct enumerators {
|
||||
constexpr static size_t size;
|
||||
|
||||
template <size_t I>
|
||||
struct get {
|
||||
constexpr const char *identifier;
|
||||
constexpr static E value;
|
||||
};
|
||||
|
||||
</em>// For enums without compile-time name trimming.<em>
|
||||
template <size_t I>
|
||||
struct get_alt {
|
||||
static const char* identifier();
|
||||
constexpr static E value;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}</em></pre><p>As you can see, the difference is that <code>identifier</code> is a non-<code>constexpr</code>
|
||||
function, and you have to access it through <code>get_alt<I></code>.</p>
|
||||
<pre class="comment">// Without compile-time name trimming.
|
||||
<em>BETTER_ENUM(Depth, int, HighColor, TrueColor)
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout
|
||||
<< std::enum_traits<Depth>::enumerators::get_alt<1>::identifier()
|
||||
<< std::endl;
|
||||
|
||||
return 0;
|
||||
}</em></pre><a id="TheFuture"></a><h3>The future</h3>
|
||||
<p>N4428 is the fourth in a series of revisions: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3815.html">N3815</a>, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4027.pdf">N4027</a>,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4113.pdf">N4113</a>, N4428. If there are more revisions that change the proposal for
|
||||
enums, I will try to implement those as well.</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
242
demo/NonIntegralUnderlyingTypes.html
Normal file
242
demo/NonIntegralUnderlyingTypes.html
Normal file
@ -0,0 +1,242 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Non-integral underlying types - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/NonIntegralUnderlyingTypes.html" />
|
||||
<meta name="description" content=""Using Better Enums with non-integral underlying types."" />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
<a href="../Contact.html">Contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.10.1</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/master/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This page is an advanced demo showing the kind of code you can write on top of
|
||||
Better Enums. It's a valid program — you can
|
||||
<a href="https://github.com/aantron/better-enums/blob/master/example/102-any-underlying.cc">download</a> it and try it out. The program runs as part of
|
||||
the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Non-integral underlying types</h2>
|
||||
<p>The underlying type of a Better Enum doesn't have to be an integral type. It can
|
||||
be any literal type <code>T</code>, as long as you provide a <code>constexpr</code> two-way mapping
|
||||
between <code>T</code> and an integral type of your choosing. This also works in <span class="cpp">C++</span><span class="eleven">98</span>
|
||||
— though then, of course, <code>T</code> doesn't have to be literal and the mapping
|
||||
doesn't have to be <code>constexpr</code>. In <span class="cpp">C++</span><span class="eleven">98</span>, everything involving <code>T</code> will simply
|
||||
be done by Better Enums at run time.</p>
|
||||
<p>This feature is semi-experimental. I am considering relaxing the requirements on
|
||||
<code>T</code> so that it doesn't have to be literal. I can use a <code>reinterpret_cast</code> to
|
||||
make a mapping automatically. This will make non-integral underlying types
|
||||
easier to use, but will also prevent usage at compile time, which unfortunately
|
||||
has structural consequences for the implementation of Better Enums, and
|
||||
additional semantic consequences for usage, even at run time.</p>
|
||||
<p>In the meantime, here's how to have a non-integral underlying type in the
|
||||
current version.</p>
|
||||
<pre>#include <iostream>
|
||||
#include <enum.h>
|
||||
typedef unsigned char uint8_t; // <cstdint> not in C++98.
|
||||
|
||||
|
||||
|
||||
// The underlying type. A color triplet.
|
||||
<em>struct html_color {
|
||||
uint8_t r, g, b;
|
||||
|
||||
constexpr html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
|
||||
r(_r), g(_g), b(_b) { }
|
||||
};</em>
|
||||
|
||||
// The mapping. It just stuffs bits to get the same effect as
|
||||
// reinterpret_cast, except reinterpret_cast is not available in constexpr
|
||||
// functions, so we have to write the bit manipulations out. On modern
|
||||
// C++11 compilers, you don't have to enter the better_enums namespace like
|
||||
// this - you can just do
|
||||
// struct ::better_enums::integral_mapping<html_color> { ...
|
||||
namespace better_enums {
|
||||
|
||||
<em>template <>
|
||||
struct integral_mapping<html_color> {
|
||||
using integral_representation = unsigned int;
|
||||
|
||||
constexpr static html_color from_integral(unsigned int i)
|
||||
{ return html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
|
||||
|
||||
constexpr static unsigned int to_integral(html_color c)
|
||||
{ return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
|
||||
};</em>
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The enum itself.
|
||||
<em>ENUM(Color, html_color,
|
||||
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954)</em></pre><p>Now, we can do:</p>
|
||||
<pre>int main()
|
||||
{
|
||||
<em>Color color = Color::darksalmon</em>;
|
||||
|
||||
std::cout << std::hex;
|
||||
std::cout << "Red component: " << <em>(int)color->r</em> << std::endl;
|
||||
std::cout << "Green component: " << <em>(int)color->g</em> << std::endl;
|
||||
std::cout << "Blue component: " << <em>(int)color->b</em> << std::endl;
|
||||
|
||||
std::cout << <em>color._to_string()</em> << std::endl;
|
||||
|
||||
<em>switch (color)</em> {
|
||||
<em>case Color::darksalmon</em>: return 0;
|
||||
<em>case Color::purplemimosa</em>: return 1;
|
||||
<em>case Color::slimegreen</em>: return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}</pre><p>This prints each component, the name of the color (<code>"darksalmon"</code>), and then
|
||||
exits from the <code>switch</code> with status 0.</p>
|
||||
<a id="ConstructorsInInitializers"></a><h3>Constructors in initializers</h3>
|
||||
<p>The above declaration used only numbers in initializers, but it is actually
|
||||
possible to use constructors of <code>html_color</code>. We have to add a <code>constexpr</code>
|
||||
converting operator directly to <code>html_color</code>, however:</p>
|
||||
<pre class="comment">struct better_html_color {
|
||||
uint8_t r, g, b;
|
||||
|
||||
constexpr better_html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
|
||||
r(_r), g(_g), b(_b) { }
|
||||
|
||||
<em>// This is new:
|
||||
constexpr operator unsigned int() const
|
||||
{ return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }</em>
|
||||
};
|
||||
|
||||
namespace better_enums {
|
||||
|
||||
template <>
|
||||
struct integral_mapping<better_html_color> {
|
||||
using integral_representation = unsigned int;
|
||||
|
||||
constexpr static better_html_color from_integral(unsigned int i)
|
||||
{
|
||||
return better_html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff);
|
||||
}
|
||||
|
||||
constexpr static unsigned int to_integral(better_html_color c)
|
||||
{ return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
|
||||
};
|
||||
|
||||
}</pre><p>This allows:</p>
|
||||
<pre class="comment">ENUM(BetterColor, better_html_color,
|
||||
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954,
|
||||
<em>celeste = better_html_color(0x50, 0xeb, 0xec)</em>)</pre><p>If you can't edit your literal type to add this converting operator, or don't
|
||||
want to for type safety reasons, you can achieve a similar effect by declaring
|
||||
an intermediate type <code>U</code> that <code>html_color</code> can convert to, that can convert to
|
||||
the integral type. Then, cast your constructor call to <code>U</code>. The type <code>U</code> is for
|
||||
declarations only.</p>
|
||||
<p>Constructors in initializers require <span class="cpp">C++</span><span class="eleven">11</span>. Also, g++ doesn't support this
|
||||
before 5.1.</p>
|
||||
<a id="LettingTheCompilerEnumerateYourType"></a><h3>Letting the compiler enumerate your type</h3>
|
||||
<p>Of course, as long as the values are valid, you can let the compiler enumerate
|
||||
your type as in a regular enum, by omitting initializers:</p>
|
||||
<pre class="comment"><em>ENUM(FD, file_descriptor, STDIN, STDOUT, STDERR, SomePipeYourDaemonHas, ...)</em></pre><p>Here, <code>FD::STDIN</code> maps to the integral representation 0, <code>STDOUT</code> to 1, and so
|
||||
on.</p>
|
||||
<a id="Discussion"></a><h3>Discussion</h3>
|
||||
<p>This feature is still semi-experimental, though I expect it to remain stable,
|
||||
except perhaps that I will make it possible to infer the type
|
||||
<code>integral_representation</code>.</p>
|
||||
<p>Any opinions are welcome.</p>
|
||||
<ul>
|
||||
<li>The main reason Better Enums needs you to supply and explicit mapping is
|
||||
because it can't just get the "bits" of objects of underlying type in
|
||||
<code>constexpr</code> code. Both <code>reinterpret_cast</code> and union abuse seem to be forbidden
|
||||
in <code>constexpr</code> functions.</li>
|
||||
<li>There is currently no way to have two different integral representaitons for
|
||||
the same underlying type in different enums. I don't think that's a major use
|
||||
case at this point, however.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015 Anton Bachin. Released under the BSD 2-clause license.
|
||||
See
|
||||
<a href="https://github.com/aantron/better-enums/blob/master/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.10.1.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
225
demo/SemiQuine.html
Normal file
225
demo/SemiQuine.html
Normal file
@ -0,0 +1,225 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Semi-quine - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/SemiQuine.html" />
|
||||
<meta name="description" content="Have a Better Enum print its own definition. Shows how to
|
||||
compute the amount of memory necessary from the reflective information provided
|
||||
by a Better Enum." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This is an example of code you can write on top of Better Enums. It's a valid
|
||||
program — you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/104-quine.cc">download</a> it and try it out. The
|
||||
program is also part of the test suite.
|
||||
</p>
|
||||
|
||||
<h2>Semi-quine</h2>
|
||||
<p>Let's make a Better Enum assemble its own definition in memory. It won't be
|
||||
literally as defined, since we will lose the exact initializer expressions, but
|
||||
we will be able to preserve the numeric values. We will reserve the memory
|
||||
buffer for the definition at compile time.</p>
|
||||
<p>Ok, so it's not really a quine, because we won't be writing all the code needed
|
||||
to generate the definition to the buffer as well. And, there are better ways to
|
||||
dump the definition than shown here. You could simply define a macro that
|
||||
expands to an <code>BETTER_ENUM</code> declaration and also stringizes it.</p>
|
||||
<p>But that's not the point here. The point of this page is to show some of the
|
||||
reflective capabilities of Better Enums, so you can adapt them for cases where a
|
||||
macro is not sufficient :)</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#ComputingTheSizeOfTheBuffer">Computing the size of the buffer</a></li><li><a href="#FormattingTheEnums">Formatting the enums</a></li><li><a href="#CheckingOurWork">Checking our work</a></li></ul></p>
|
||||
<hr>
|
||||
<pre>#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <iostream></pre><hr>
|
||||
<p>First, we will need
|
||||
<a href="../OptInFeatures.html#CompileTimeNameTrimming">full compile-time reflection</a>,
|
||||
since we will be calling <code>_to_string</code>. Let's make sure it's enabled by defining
|
||||
<code>BETTER_ENUMS_CONSTEXPR_TO_STRING</code> before including <code>enum.h</code>:</p>
|
||||
<pre>#ifndef <em>BETTER_ENUMS_CONSTEXPR_TO_STRING</em>
|
||||
#define <em>BETTER_ENUMS_CONSTEXPR_TO_STRING</em>
|
||||
#endif
|
||||
|
||||
<em>#include <enum.h></em></pre><p>Now, let's declare some enums to dump later:</p>
|
||||
<pre>BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue)
|
||||
BETTER_ENUM(<em>Depth</em>, int, TrueColor = 1, HighColor = 0)</pre><a id="ComputingTheSizeOfTheBuffer"></a><h3>Computing the size of the buffer</h3>
|
||||
<p>First, we need to be able to get the length of each declaration above. We will
|
||||
assume that the underlying type is always <code>int</code>, and that the spacing convention
|
||||
is followed as above.</p>
|
||||
<p>First, let's get the lengths of basic components:</p>
|
||||
<pre>// Returns the length of the string representation of the number n
|
||||
constexpr <em>size_t value_length</em>(int <em>n</em>, int bound = 10, size_t digits = 1)
|
||||
{
|
||||
return
|
||||
<em>n < bound ? digits : value_length(n, bound * 10, digits + 1)</em>;
|
||||
}
|
||||
|
||||
// Returns the length of s
|
||||
constexpr <em>size_t string_length</em>(const char *<em>s</em>, size_t index = 0)
|
||||
{
|
||||
return <em>s[index] == '\0' ? index : string_length(s, index + 1)</em>;
|
||||
}</pre><p>Now, the length of the constant declaration. Here is where we lose information
|
||||
about initializers. We are going to format the constant declarations like this:</p>
|
||||
<pre class="comment">Red = 0, Green = 1, Blue = 2
|
||||
TrueColor = 1, HighColor = 0</pre><p>This is because Better Enums doesn't provide a way to know what the exact
|
||||
initializer was or whether there even was one — just the numeric value of
|
||||
each constant. If we were trying to be clever, we could avoid formatting
|
||||
initializers for sequential values, but I won't go through this exercise here.</p>
|
||||
<pre>// Returns the length of the constants portion of the declaration of Enum,
|
||||
// as described above.
|
||||
template <<em>typename Enum</em>>
|
||||
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
constants_length<Enum>(
|
||||
index + 1, accumulator
|
||||
+ string_length(", ")
|
||||
+ string_length(Enum::_names()[index])
|
||||
+ string_length(" = ")
|
||||
+ value_length(
|
||||
Enum::_values()[index]._to_integral()))</em>;
|
||||
}</pre><p>Finally, we can combine these to get the length of the formatted declaration of
|
||||
the whole enum:</p>
|
||||
<pre>// Returns the length of the whole declaration of Enum, assuming the
|
||||
// underlying type is int, and the constants are initialized as assumed by
|
||||
// constants_length() above.
|
||||
template <<em>typename Enum</em>>
|
||||
constexpr <em>size_t declaration_length</em>()
|
||||
{
|
||||
return
|
||||
<em>string_length("BETTER_ENUM(")
|
||||
+ string_length(Enum::_name())
|
||||
+ string_length(", int")
|
||||
+ constants_length<Enum>()
|
||||
+ string_length(")")</em>;
|
||||
}</pre><a id="FormattingTheEnums"></a><h3>Formatting the enums</h3>
|
||||
<p>Now, we can declare the buffers. The memory will be reserved at load time by the
|
||||
binary's loader. The extra one byte in each buffer is for the null terminator.</p>
|
||||
<pre><em>char</em> channel_definition[<em>declaration_length<Channel>() + 1</em>];
|
||||
<em>char</em> depth_definition[<em>declaration_length<Depth>() + 1</em>];</pre><p>Let's also create the formatting function. This is executed at run time, but we
|
||||
will be giving it pointers to our statically-allocated buffers. It will format
|
||||
the enum declaration and then return the number of bytes it wrote to the buffer,
|
||||
so that we can do a sanity check on it.</p>
|
||||
<pre>template <<em>typename Enum</em>>
|
||||
<em>size_t format</em>(char *<em>buffer</em>)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
offset += std::sprintf(buffer, <em>"BETTER_ENUM(%s, int", Enum::_name()</em>);
|
||||
|
||||
<em>for</em> (<em>Enum value</em> : <em>Enum::_values()</em>) {
|
||||
offset +=
|
||||
std::sprintf(buffer + offset,
|
||||
<em>", %s = %i",
|
||||
value._to_string(), value._to_integral()</em>);
|
||||
}
|
||||
|
||||
offset += std::sprintf(buffer + offset, <em>")"</em>);
|
||||
|
||||
return <em>offset</em>;
|
||||
}</pre><a id="CheckingOurWork"></a><h3>Checking our work</h3>
|
||||
<p>Now, we can write and run this code.</p>
|
||||
<pre>int main()
|
||||
{
|
||||
size_t channel_length = <em>format<Channel></em>(channel_definition);
|
||||
assert(channel_length + 1 == sizeof(channel_definition));
|
||||
|
||||
size_t depth_length = <em>format<Depth></em>(depth_definition);
|
||||
assert(depth_length + 1 == sizeof(depth_definition));
|
||||
|
||||
std::cout << <em>channel_definition</em> << std::endl;
|
||||
std::cout << <em>depth_definition</em> << std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><p>It prints:</p>
|
||||
<pre class="comment">BETTER_ENUM(Channel, int, Red = 0, Green = 1, Blue = 2)
|
||||
BETTER_ENUM(Depth, int, TrueColor = 1, HighColor = 0)</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
220
demo/SpecialValues.html
Normal file
220
demo/SpecialValues.html
Normal file
@ -0,0 +1,220 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Special values - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/demo/SpecialValues.html" />
|
||||
<meta name="description" content="An example that uses Better Enums compile-time reflection to
|
||||
create invalid and default values for each enum, enforced statically by the
|
||||
compiler, for readability and maintainability." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
This is an example of code you can write on top of Better Enums. It's a valid
|
||||
program — you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/101-special-values.cc">download</a> it and try it out. The
|
||||
program is also part of the test suite.
|
||||
</p>
|
||||
|
||||
<h2>Special values</h2>
|
||||
<p>Suppose your project has a convention where each enum has special <em>invalid</em> and
|
||||
<em>default</em> values — for example, <code>Enum::Invalid</code> is <em>invalid</em>, and the
|
||||
first valid constant is <em>default</em>. With Better Enums, you can get the compiler
|
||||
to enforce the convention. At the end of this demo, we will have defined
|
||||
functions and templates that allow us to write:</p>
|
||||
<pre class="comment"><em>Channel channel</em> = <em>default_</em>;
|
||||
<em>Channel channel</em> = <em>invalid</em>;
|
||||
|
||||
void do_something(<em>Channel channel</em>);
|
||||
|
||||
do_something(<em>default_</em>);
|
||||
do_something(<em>invalid</em>);</pre><p>The compiler will compute default and invalid values automatically, but the
|
||||
programmer will also be able to override the choice. Obviously, the syntax above
|
||||
is very legible and maintainable — the intent is clear and your code base
|
||||
will respond automatically to changes in enum definitions.</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#InvalidValues">Invalid values</a></li><li><a href="#DefaultValues">Default values</a></li><li><a href="#MakingTheSyntaxNicer">Making the syntax nicer</a></li></ul></p>
|
||||
<a id="InvalidValues"></a><h3>Invalid values</h3>
|
||||
<p>Let's start by defining the invalid values.</p>
|
||||
<pre>#include <iostream>
|
||||
#include <stdexcept>
|
||||
<em>#include <enum.h></em></pre><p>Perhaps the convention is that the invalid value is usually called <code>Invalid</code>,
|
||||
but not for all enums. We will encode that using a template function. The
|
||||
unspecialized version will encode the default policy:</p>
|
||||
<pre><em>template</em> <<em>typename Enum</em>>
|
||||
constexpr <em>Enum invalid_impl</em>() { return <em>Enum::Invalid</em>; }</pre><p>A macro allows us to override the invalid value by specializing the template:</p>
|
||||
<pre><em>#define OVERRIDE_INVALID</em>(<em>Enum</em>, <em>Value</em>) \
|
||||
template<> \
|
||||
constexpr <em>Enum invalid_impl</em><<em>Enum</em>>() { return <em>Enum::Value</em>; }</pre><p>Now, we can declare enums like these:</p>
|
||||
<pre>BETTER_ENUM(<em>Channel</em>, int, Red, Green, Blue, <em>Invalid</em>)
|
||||
// Invalid is the invalid value by default
|
||||
|
||||
BETTER_ENUM(<em>Compression</em>, int, <em>Undefined</em>, None, Huffman)
|
||||
OVERRIDE_INVALID(<em>Compression</em>, <em>Undefined</em>)</pre><p>and use them:</p>
|
||||
<pre>static_assert(<em>invalid_impl</em><<em>Channel</em>>() == +<em>Channel::Invalid</em>, "");
|
||||
static_assert(<em>invalid_impl</em><<em>Compression</em>>() == +<em>Compression::Undefined</em>, "");</pre><p>This even supports enums that don't have an invalid value at all. As long as
|
||||
they don't have a constant called <code>Invalid</code>, you will get a compile-time error
|
||||
if you try to call <code>invalid_impl<>()</code> on them — as you probably should!</p>
|
||||
<a id="DefaultValues"></a><h3>Default values</h3>
|
||||
<p>Perhaps here the convention is the first value that is not invalid is default,
|
||||
unless, again, overridden by the programmer. This can be encoded using only a
|
||||
slightly more complex template function for the general case:</p>
|
||||
<pre><em>template</em> <<em>typename Enum</em>>
|
||||
constexpr <em>Enum default_imp</em>l()
|
||||
{
|
||||
return
|
||||
<em>Enum::_size() < 2 ?
|
||||
throw std::logic_error("enum has no valid constants") :
|
||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||
Enum::_values()[1] :
|
||||
Enum::_values()[0]</em>;
|
||||
}</pre><p>The above code gives us the first value if it is not invalid, otherwise the
|
||||
second value.</p>
|
||||
<p>The companion macro for overriding the choice of default value is almost the
|
||||
same as it was for invalid. The difference is that we do an extra sanity check
|
||||
to make sure the programmer doesn't declare the invalid value to be the default.
|
||||
If the sanity check fails, we produce a nice error message. Again, we are
|
||||
assuming that this is dictated by policy.</p>
|
||||
<pre><em>#define OVERRIDE_DEFAULT</em>(<em>Enum</em>, <em>Value</em>) \
|
||||
static_assert(<em>Enum::Value</em> != <em>Enum::Invalid</em>, \
|
||||
<em>#Enum ": default cannot equal invalid"</em>); \
|
||||
template<> \
|
||||
constexpr <em>Enum default_impl</em><<em>Enum</em>>() { return <em>Enum::Value</em>; }</pre><p>And, as before, the usage:</p>
|
||||
<pre>static_assert(<em>default_impl</em><<em>Channel</em>>() == +<em>Channel::Red</em>, "");
|
||||
static_assert(<em>default_impl</em><<em>Compression</em>>() == +<em>Compression::None</em>, "");</pre><p>And, if you do</p>
|
||||
<pre>BETTER_ENUM(<em>Answer</em>, int, Yes, No, <em>Invalid</em>)
|
||||
// OVERRIDE_DEFAULT(<em>Answer</em>, <em>Invalid</em>)</pre><p>you will get a helpful compile-time error saying
|
||||
<code>Answer: default cannot equal invalid</code>.</p>
|
||||
<a id="MakingTheSyntaxNicer"></a><h3>Making the syntax nicer</h3>
|
||||
<p>At this point, our policy is encoded by the ugly-looking functions
|
||||
<code>invalid_impl</code> and <code>default_impl</code>. We want a nicer syntax. The main reason we
|
||||
don't just use these functions directly is that the compiler wouldn't infer
|
||||
their template arguments from the context. For example, we would have to write
|
||||
things like</p>
|
||||
<pre class="comment">Channel channel = invalid_impl<Channel>();</pre><p>which is unfortunate, because it results in repetition.</p>
|
||||
<p>In this section, we introduce two global objects called <code>invalid</code> and <code>default_</code>
|
||||
that will implicitly convert to any Better Enum type, and provide the invalid
|
||||
or default value, respectively, when they do so. They will act as new
|
||||
"keywords".</p>
|
||||
<pre><em>struct invalid_t</em> {
|
||||
template <<em>typename To</em>>
|
||||
constexpr <em>operator To</em>() const { return <em>invalid_impl<To>()</em>; }
|
||||
};
|
||||
|
||||
<em>struct default_t</em> {
|
||||
template <<em>typename To</em>>
|
||||
constexpr <em>operator To</em>() const { return <em>default_impl<To>()</em>; }
|
||||
};
|
||||
|
||||
constexpr <em>invalid_t invalid</em>{};
|
||||
constexpr <em>default_t default_</em>{};</pre><p>As you can see, both of these provide the families of implicit conversions that
|
||||
we need. Now, we can test:</p>
|
||||
<pre>static_assert(+<em>Channel::Invalid</em> == <em>invalid</em>, "");
|
||||
static_assert(+<em>Compression::Undefined</em> == <em>invalid</em>, "");
|
||||
|
||||
static_assert(+<em>Channel::Red</em> == <em>default_</em>, "");
|
||||
static_assert(+<em>Compression::None</em> == <em>default_</em>, "");</pre><p>Finally, we can have nice code such as this:</p>
|
||||
<pre>void dump(<em>Channel channel</em>)
|
||||
{
|
||||
std::cout << channel._to_string() << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
dump(<em>invalid</em>);
|
||||
|
||||
<em>Channel channel</em> = <em>default_</em>;
|
||||
dump(channel);
|
||||
|
||||
return 0;
|
||||
}</pre><hr>
|
||||
<p>There are many possible variations of these policies, but I think most of them
|
||||
can be encoded in a reasonable fashion using the tools Better Enums provides.
|
||||
Enjoy!</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
Return to the <a href="../index.html#CompileTimeDemos">demo index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
image/tweet.png
Normal file
BIN
image/tweet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
BIN
image/twsupport.png
Normal file
BIN
image/twsupport.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
313
index.html
Normal file
313
index.html
Normal file
@ -0,0 +1,313 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Better Enums - Clean reflective enums for C++</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums" />
|
||||
<meta name="description" content="Reflective enums in a single header file, with clean syntax.
|
||||
The enums can be converted to string, iterated, and counted, at run time or
|
||||
as part of metaprogramming. Free and open source under the BSD license." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="index">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<div class="splash">
|
||||
<pre class="left">enable
|
||||
|
||||
declare
|
||||
|
||||
|
||||
parse
|
||||
format
|
||||
|
||||
|
||||
count
|
||||
iterate
|
||||
|
||||
|
||||
|
||||
|
||||
switch
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
safe cast
|
||||
|
||||
|
||||
during
|
||||
compilation
|
||||
</pre>
|
||||
<pre class="right"><em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red = 1, Green, Blue)</em>
|
||||
|
||||
|
||||
Channel c = <em>Channel::_from_string("Red")</em>;
|
||||
const char *s = <em>c._to_string()</em>;
|
||||
|
||||
|
||||
size_t n = <em>Channel::_size()</em>;
|
||||
<em>for (Channel c : Channel::_values())</em> {
|
||||
run_some_function(c);
|
||||
}
|
||||
|
||||
|
||||
<em>switch (c)</em> {
|
||||
<em>case Channel::Red</em>: // ...
|
||||
<em>case Channel::Green</em>: // ...
|
||||
<em>case Channel::Blue</em>: // ...
|
||||
}
|
||||
|
||||
|
||||
Channel c = <em>Channel::_from_integral(3)</em>;
|
||||
|
||||
|
||||
<em>constexpr</em> Channel c =
|
||||
<em>Channel::_from_string("Blue")</em>;</pre>
|
||||
</div>
|
||||
|
||||
<p class="splash-text">
|
||||
<span class="self">Better Enums</span> is a single, lightweight header file that makes your compiler generate
|
||||
<em>reflective</em> enum types.
|
||||
</p>
|
||||
|
||||
<p>That means you can easily convert enums to and from strings,
|
||||
validate them, and loop over them. In <span class="cpp">C++</span><span class="eleven">11</span>, you can do it all at
|
||||
compile time.</p>
|
||||
<p>It's what built-in enums ought to support. Better Enums simply adds the missing
|
||||
features. And, it is based on the best known techniques, thoroughly tested,
|
||||
fast, portable, and documented exhaustively.</p>
|
||||
<p>To use it, just include <code>enum.h</code> and begin the
|
||||
<a href="tutorial/HelloWorld.html">tutorial</a>!</p>
|
||||
<div class="hack"></div>
|
||||
|
||||
<a id="Highlights"></a><h3>Highlights</h3>
|
||||
<ul class="blurbs">
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<strong>Unobtrusive syntax</strong>
|
||||
<em>
|
||||
No ugly macros. Use initializers as with built-in <code>enums</code>.
|
||||
Internal members have underscores to avoid clashing with your constant
|
||||
names.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<strong>No external dependencies</strong>
|
||||
<em>
|
||||
Uses only standard <span class="cpp">C++</span>. Installation is simple — just download
|
||||
<code>enum.h</code>. There are no objects or libraries to link with.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<strong>No generator program needed</strong>
|
||||
<em>
|
||||
Just include <code>enum.h</code>. It's a metaprogram executed by your
|
||||
compiler.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two zero-mod-three">
|
||||
<strong>Plays nice with <code>switch</code></strong>
|
||||
<em>
|
||||
Use a Better Enum like a built-in <code>enum</code>, and still have the
|
||||
compiler do case checking.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two one-mod-three">
|
||||
<strong>Don't repeat yourself</strong>
|
||||
<em>
|
||||
No more unmaintanable maps or <code>switch</code> statements for
|
||||
converting enums to strings.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two two-mod-three">
|
||||
<strong>Non-contiguous sequences</strong>
|
||||
<em>
|
||||
Iteration and counting are much easier to maintain than with an extra
|
||||
<code>Count</code> constant and assuming a dense range.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<strong>Fast compilation</strong>
|
||||
<em>
|
||||
Much less impact on build time than even just including
|
||||
<code>iostream</code>. <code>enum.h</code> is only slightly more than 1000
|
||||
lines long.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<strong>Compile-time reflection</strong>
|
||||
<em>
|
||||
Have the compiler do additional enum processing using your own
|
||||
templates or <code>constexpr</code> functions.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<strong>Uniform interface for <span class="cpp">C++</span><span class="eleven">98</span>, <span class="cpp">C++</span><span class="eleven">11</span></strong>
|
||||
<em>
|
||||
Scoped, sized, reflective enums for <span class="cpp">C++</span><span class="eleven">98</span>, and an easy upgrade
|
||||
path.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two zero-mod-three">
|
||||
<strong>Stream operators</strong>
|
||||
<em>
|
||||
Write enum names directly to <code>std::cout</code> or use
|
||||
<code>boost::lexical_cast</code>.
|
||||
</em>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two one-mod-three">
|
||||
<strong>Free and open source</strong>
|
||||
<em>
|
||||
Released under the BSD license for use in any project, free or commercial.
|
||||
</em>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="hack"></div>
|
||||
|
||||
<a id="Documentation"></a><h3>Documentation</h3>
|
||||
<ul class="blurbs resources">
|
||||
<li class="zero-mod-two zero-mod-three">
|
||||
<a id="Tutorial"></a>
|
||||
<strong>Tutorial</strong>
|
||||
<ol>
|
||||
<li><a href="tutorial/HelloWorld.html">Hello, World!</a></li>
|
||||
<li><a href="tutorial/Conversions.html">Conversions</a></li>
|
||||
<li><a href="tutorial/Iteration.html">Iteration</a></li>
|
||||
<li><a href="tutorial/SafeSwitch.html">Safe switch</a></li>
|
||||
<li><a href="tutorial/Maps.html">Maps</a></li>
|
||||
<li><a href="tutorial/StreamOperators.html">Stream operators</a></li>
|
||||
<li><a href="tutorial/ScopeAndSafety.html">Scope and safety</a></li>
|
||||
<li><a href="tutorial/Representation.html">Representation</a></li>
|
||||
<li><a href="tutorial/CompileTimeUsage.html">Compile-time usage</a></li>
|
||||
|
||||
</ol>
|
||||
</li>
|
||||
|
||||
<li class="one-mod-two one-mod-three">
|
||||
<strong>Reference</strong>
|
||||
<ul>
|
||||
<li><a href="ApiReference.html">API reference</a></li>
|
||||
<li><a href="CompilerSupport.html">Compiler support</a></li>
|
||||
<li><a href="OptInFeatures.html">Opt-in features</a></li>
|
||||
<li><a href="ExtendingLimits.html">Extending limits</a></li>
|
||||
<li><a href="Performance.html">Performance</a></li>
|
||||
<li>
|
||||
<a href="DesignDecisionsFAQ.html">Design decisions FAQ</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.codeproject.com/Articles/1002895/Clean-Reflective-Enums-Enum-to-String-with-Nice-Sy">
|
||||
Implementation <span class="external">[CodeProject]</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="zero-mod-two two-mod-three">
|
||||
<a id="CompileTimeDemos"></a>
|
||||
<strong>Advanced</strong>
|
||||
<ul>
|
||||
<li><a href="demo/SpecialValues.html">Special values</a></li>
|
||||
<li><a href="demo/BitSets.html">Bit sets</a></li>
|
||||
<li><a href="demo/SemiQuine.html">Semi-quine</a></li>
|
||||
<li><a href="demo/C++17ReflectionProposal.html">C++17 reflection proposal</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="hack"></div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
64
sitemap.xml
Normal file
64
sitemap.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/HelloWorld.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/Conversions.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/Iteration.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/SafeSwitch.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/Maps.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/StreamOperators.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/ScopeAndSafety.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/Representation.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/tutorial/CompileTimeUsage.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/demo/SpecialValues.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/demo/BitSets.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/demo/SemiQuine.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/ApiReference.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/CompilerSupport.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/DesignDecisionsFAQ.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/ExtendingLimits.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums</loc>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/OptInFeatures.html</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://aantron.github.io/better-enums/Performance.html</loc>
|
||||
</url>
|
||||
</urlset>
|
||||
148
tutorial/CompileTimeUsage.html
Normal file
148
tutorial/CompileTimeUsage.html
Normal file
@ -0,0 +1,148 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Compile-time usage - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/CompileTimeUsage.html" />
|
||||
<meta name="description" content="Better Enums can be used entirely at compile time in C++11. All
|
||||
conversion functions are available for constexpr functions or templates." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/9-constexpr.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Compile-time usage</h2>
|
||||
<p>When used with <span class="cpp">C++</span><span class="eleven">11</span>, Better Enums are generated entirely during compilation.
|
||||
All the data is available for use by your own <code>constexpr</code> functions. The
|
||||
examples in <em>this</em> tutorial aren't very useful, but look at the
|
||||
<a href="../index.html#CompileTimeDemos">demos</a> at the bottom of the main page to
|
||||
get an idea of what can be done. Here, you will see the basics.</p>
|
||||
<pre>#include <iostream>
|
||||
|
||||
// The reason for this is explained below.
|
||||
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
|
||||
#endif
|
||||
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)
|
||||
|
||||
<em>constexpr</em> Channel channel = <em>Channel::_from_integral(2)</em>;
|
||||
<em>constexpr</em> int value = <em>channel._to_integral()</em>;
|
||||
|
||||
<em>constexpr</em> const char *name = <em>channel._to_string()</em>;
|
||||
<em>constexpr</em> Channel parsed = <em>Channel::_from_string("Red")</em>;</pre><p>All of the above are computed during compilation. The reason for the macro
|
||||
definition at the top of the file is explained on the
|
||||
<a href="../OptInFeatures.html#CompileTimeNameTrimming">opt-in features page</a>.
|
||||
Basically, it makes <code>_to_string</code> <code>constexpr</code>, but slows down compilation.</p>
|
||||
<p>You can also do things such as:</p>
|
||||
<pre><em>constexpr size_t length</em>(<em>const char *s</em>, <em>size_t index = 0</em>)
|
||||
{
|
||||
return <em>s[index] == '\0'</em> ? <em>index</em> : <em>length(s, index + 1)</em>;
|
||||
}
|
||||
|
||||
<em>constexpr</em> size_t <em>length_of_name_of_second_constant</em> =
|
||||
<em>length(Channel::_names()[1])</em>;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>length_of_name_of_second_constant</em> << std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><p>Which prints "5", the length of "Green". That 5 was also computed during
|
||||
compilation.</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="up">
|
||||
This is the last tutorial! Return to the
|
||||
<a href="../index.html">main page</a> for other resources.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
211
tutorial/Conversions.html
Normal file
211
tutorial/Conversions.html
Normal file
@ -0,0 +1,211 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Conversions - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/Conversions.html" />
|
||||
<meta name="description" content="Better Enums conversion functions. Converting to string, from
|
||||
string, to int, from int, and validation, both case-sensitive and
|
||||
case-insensitive. Exception-throwing and non-throwing variants presented." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/2-conversions.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Conversions</h2>
|
||||
<p>Let's begin by including <code>enum.h</code> and declaring our enum:</p>
|
||||
<pre>#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Cyan</em> = <em>1</em>, <em>Magenta</em>, <em>Yellow</em>, <em>Black</em>)</pre><p>We now have an <code>int</code>-sized enum with four constants.</p>
|
||||
<p>There are three groups of conversion functions: for strings, case-insensitive
|
||||
strings, and integers. They all follow the same pattern, so I'll explain the
|
||||
string functions in detail, and the rest can be understood by analogy.</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#Strings">Strings</a></li><li><a href="#CaseInsensitiveStrings">Case-insensitive strings</a></li><li><a href="#Integers">Integers</a></li><li><a href="#ValidityChecking">Validity checking</a></li></ul></p>
|
||||
<a id="Strings"></a><h3>Strings</h3>
|
||||
<p>There are three functions:</p>
|
||||
<ol>
|
||||
<li><code>._to_string</code></li>
|
||||
<li><code>::_from_string</code></li>
|
||||
<li><code>::_from_string_nothrow</code></li>
|
||||
</ol>
|
||||
<pre>int main()
|
||||
{
|
||||
<em>Channel channel = Channel::Cyan</em>;
|
||||
std::cout << <em>channel._to_string()</em> << " ";</pre><p>As you'd expect, the code above prints "Cyan".</p>
|
||||
<p>If <code>channel</code> is invalid — for example, if you simply cast the number "42"
|
||||
to <code>Channel</code> — then the result of <code>to_string</code> is undefined.</p>
|
||||
<hr>
|
||||
<pre> channel = <em>Channel::_from_string("Magenta")</em>;
|
||||
std::cout << channel._to_string() << " ";</pre><p>This is also straightforward. If you pass a string which is not the name of a
|
||||
declared value, <code>_from_string</code> throws <code>std::runtime_error</code>.</p>
|
||||
<hr>
|
||||
<p>If you don't want an exception, there is <code>_from_string_nothrow</code>:</p>
|
||||
<pre> <em>better_enums::optional<Channel></em> maybe_channel =
|
||||
<em>Channel::_from_string_nothrow("Yellow")</em>;
|
||||
|
||||
if (<em>!maybe_channel</em>)
|
||||
std::cout << "error";
|
||||
else
|
||||
std::cout << <em>maybe_channel-></em>_to_string() << " ";</pre><p>This returns an <em>optional value</em>, in the style of
|
||||
<a href="http://www.boost.org/doc/libs/1_58_0/libs/optional/doc/html/index.html"><code>boost::optional</code></a>
|
||||
or the proposed
|
||||
<a href="http://en.cppreference.com/w/cpp/experimental/optional"><code>std::optional</code></a>.</p>
|
||||
<p>What that means for the above code is:</p>
|
||||
<ul>
|
||||
<li>if the conversion succeeds, <code>maybe_channel</code> converts to <code>true</code> and
|
||||
<code>*maybe_channel</code> is the converted value of type <code>Channel</code>,</li>
|
||||
<li>if the conversion fails, <code>maybe_channel</code> converts to <code>false</code>.</li>
|
||||
</ul>
|
||||
<p>In <span class="cpp">C++</span><span class="eleven">11</span>, you can use <code>auto</code> to avoid writing out the optional type:</p>
|
||||
<pre class="comment"> <em>auto</em> maybe_channel = <em>Channel::_from_string_nothrow("Yellow")</em>;
|
||||
if (<em>!maybe_channel</em>)
|
||||
std::cout << "error";
|
||||
else
|
||||
std::cout << <em>maybe_channel-></em>_to_string() << " ";</pre><a id="CaseInsensitiveStrings"></a><h3>Case-insensitive strings</h3>
|
||||
<p>The "<code>_nocase</code>" string conversions follow the same pattern, except for the lack
|
||||
of a "<code>to_string_nocase</code>".</p>
|
||||
<ol>
|
||||
<li><code>::_from_string_nocase</code></li>
|
||||
<li><code>::_from_string_nocase_nothrow</code></li>
|
||||
</ol>
|
||||
<pre> channel = <em>Channel::_from_string_nocase("cYaN")</em>;
|
||||
std::cout << channel._to_string() << " ";
|
||||
|
||||
maybe_channel = <em>Channel::_from_string_nocase_nothrow("rEeD")</em>;
|
||||
assert(!maybe_channel);</pre><a id="Integers"></a><h3>Integers</h3>
|
||||
<p>And, it is similar with the <em>representation type</em> <code>int</code>:</p>
|
||||
<ol>
|
||||
<li><code>._to_integral</code></li>
|
||||
<li><code>::_from_integral</code></li>
|
||||
<li><code>::_from_integral_nothrow</code></li>
|
||||
<li><code>::_from_integral_unchecked</code></li>
|
||||
</ol>
|
||||
<pre> channel = Channel::Cyan;
|
||||
std::cout << <em>channel._to_integral()</em> << " ";
|
||||
|
||||
channel = <em>Channel::_from_integral(2)</em>;
|
||||
std::cout << channel._to_string() << " ";
|
||||
|
||||
maybe_channel = <em>Channel::_from_integral_nothrow(0)</em>;
|
||||
assert(<em>!maybe_channel</em>);</pre><p>That prints "1 Magenta".</p>
|
||||
<p><code>_from_integral_unchecked</code> is a no-op unchecked cast of integers to enums, so
|
||||
use it carefully.</p>
|
||||
<pre> channel = <em>Channel::_from_integral_unchecked(0)</em>;
|
||||
// <em>Invalid</em> - better not to try converting it to string!</pre><a id="ValidityChecking"></a><h3>Validity checking</h3>
|
||||
<p>For completeness, Better Enums also provides three validity checking functions,
|
||||
one for each of the groups of conversions — string, case-insensitive
|
||||
string, and integer:</p>
|
||||
<pre> assert(<em>Channel::_is_valid(3)</em>);
|
||||
assert(<em>Channel::_is_valid("Magenta")</em>);
|
||||
assert(<em>Channel::_is_valid_nocase("cYaN")</em>);</pre><hr>
|
||||
<p>Almost done.</p>
|
||||
<p>There is one unfortunate wrinkle. You cannot convert a literal constant such as
|
||||
<code>Channel::Cyan</code> directly to, for example, a string. You have to prefix it with
|
||||
<code>+</code>:</p>
|
||||
<pre> std::cout << (<em>+Channel::Cyan</em>)._to_string();</pre><p>This is due to some type gymnastics in the implementation of Better Enums. The
|
||||
reference has a
|
||||
<a href="../ApiReference.html#HelperFunctionsAndTypes">full explanation</a>.</p>
|
||||
<hr>
|
||||
<pre> std::cout << std::endl;
|
||||
return 0;
|
||||
}</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/Iteration.html">Iteration</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
128
tutorial/HelloWorld.html
Normal file
128
tutorial/HelloWorld.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Hello, World! - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/HelloWorld.html" />
|
||||
<meta name="description" content="Introductory Better Enums tutorial - a simple, but complete,
|
||||
Hello World program." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/1-hello-world.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Hello, World!</h2>
|
||||
<p>Download <a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download><code>enum.h</code></a>, then compile this program:</p>
|
||||
<pre>#include <iostream>
|
||||
<em>#include "enum.h"</em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Word</em>, <em>int</em>, <em>Hello</em>, <em>World</em>)
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>(+Word::Hello)._to_string()</em> << ", "
|
||||
<< <em>(+Word::World)._to_string()</em> << "!"
|
||||
<< std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><p>Run it, and you should see the output "Hello, World!"</p>
|
||||
<p>Congratulations, you have just created your first Better Enum!</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/Conversions.html">Conversions</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
142
tutorial/Iteration.html
Normal file
142
tutorial/Iteration.html
Normal file
@ -0,0 +1,142 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Iteration - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/Iteration.html" />
|
||||
<meta name="description" content="Using Better Enums to iterate over all the constants of an
|
||||
enum, as well as over its names. Also shows the same with C++11 for-each syntax." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/3-iterate.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Iteration</h2>
|
||||
<p>Better Enums makes it easy to iterate over the values you have declared. For
|
||||
example, this:</p>
|
||||
<pre>#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green = 2, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
Channel channel = <em>Channel::_values()[index]</em>;
|
||||
std::cout << channel._to_integral() << " ";
|
||||
}
|
||||
std::cout << std::endl;</pre><p>will print "0 2 3". And this:</p>
|
||||
<pre> <em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
const char *name = <em>Channel::_names()[index]</em>;
|
||||
std::cout << name << " ";
|
||||
}
|
||||
std::cout << std::endl;</pre><p>will print "Red Green Blue".</p>
|
||||
<hr>
|
||||
<p>If you are using <span class="cpp">C++</span><span class="eleven">11</span>, you can have much nicer syntax:</p>
|
||||
<pre class="comment"> <em>for (Channel channel : Channel::_values())</em>
|
||||
std::cout << <em>channel._to_integral()</em> << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
<em>for (const char *name : Channel::_names())</em>
|
||||
std::cout << <em>name</em> << " ";
|
||||
std::cout << std::endl;</pre><hr>
|
||||
<pre> return 0;
|
||||
}</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/SafeSwitch.html">Safe switch</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
162
tutorial/Maps.html
Normal file
162
tutorial/Maps.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Maps - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/Maps.html" />
|
||||
<meta name="description" content="Mapping enums to arbitrary types and vice versa." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/5-map.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Maps</h2>
|
||||
<p>It is possible to create <code>constexpr</code> bidirectional maps between Better Enums and
|
||||
any type. This is currently an experimental feature. Feedback is very much
|
||||
wanted, but please don't build any mission-critical code on top of this :)</p>
|
||||
<p>The way it works is you give Better Enums a function — say,
|
||||
<code>const char* describe(Channel)</code>. The library enumerates it to make a map.</p>
|
||||
<p>The reason for using a function is that a <code>switch</code> statement is, I believe, the
|
||||
only place where a compiler will check for exhaustiveness. If you forget to
|
||||
create a case for one of the enum's constants, the compiler can let you know.
|
||||
Obviously, a <code>switch</code> statement is not data, and needs to be inside a function.
|
||||
It can only be inside a <code>constexpr</code> function in <span class="cpp">C++</span><span class="eleven">14</span>, so this feature is most
|
||||
natural in <span class="cpp">C++</span><span class="eleven">14</span>. When you pass the function to Better Enums, the library can
|
||||
build up a lookup data structure at compile time.</p>
|
||||
<p>Actually, right now, Better Enums doesn't quite do that — it enumerates
|
||||
the function <em>every</em> time you want to convert to an enum (but not <em>from</em> an
|
||||
enum). It simply does a linear scan every time. This is because I haven't yet
|
||||
found a data structure whose compile-time generation is fast enough for
|
||||
practical use.</p>
|
||||
<hr>
|
||||
<pre>#include <iostream>
|
||||
<em>#include</em> <<em>enum.h</em>>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em>, <em>Green</em>, <em>Blue</em>)</pre><p>We will create a map from this function:</p>
|
||||
<pre>constexpr <em>const char* describe</em>(<em>Channel channel</em>)
|
||||
{
|
||||
switch(<em>channel</em>) {
|
||||
case <em>Channel::Red</em>: return <em>"the red channel"</em>;
|
||||
case <em>Channel::Green</em>: return <em>"the green channel"</em>;
|
||||
case <em>Channel::Blue</em>: return <em>"the blue channel"</em>;
|
||||
}
|
||||
|
||||
return "needed for gcc 5";
|
||||
}</pre><p>Here is the map. The actual type is <code>better_enums::map<Channel, const char*></code>.</p>
|
||||
<pre>constexpr auto <em>descriptions</em> = <em>better_enums::make_map</em>(<em>describe</em>);</pre><p>And the usage:</p>
|
||||
<pre>int main()
|
||||
{
|
||||
std::cout << <em>descriptions[Channel::Red]</em> << std::endl;
|
||||
|
||||
std::cout << <em>descriptions</em>.<em>from_enum</em>(<em>Channel::Red</em>) << std::endl;
|
||||
std::cout << <em>descriptions</em>.<em>to_enum</em>(<em>"the green channel"</em>) << std::endl;
|
||||
|
||||
auto <em>not_a_literal</em> = <em>std::string</em>(<em>"the blue channel"</em>);
|
||||
std::cout << <em>descriptions</em>.<em>to_enum</em>(<em>not_a_literal</em>.<em>c_str()</em>) << std::endl;
|
||||
|
||||
return 0;
|
||||
}</pre><hr>
|
||||
<p><code>make_map</code> above produces a value of type <code>better_enums::map<E, T></code>. The full
|
||||
signature of the template <code>better_enums::map</code> is</p>
|
||||
<pre class="comment"><em>template <typename Enum, typename T, typename Compare = map_compare<T>></em></pre><p><code>Compare</code> has to be a class with a static member function
|
||||
<code>bool less(const T&, const T&)</code>. The default implementation
|
||||
<code>better_enums::map_compare</code> simply applies <code>operator <</code>, except when <code>T</code> is
|
||||
<code>const char*</code> or <code>const wchar_t*</code>. In that case, it does lexicographic comparison.</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/StreamOperators.html">Stream operators</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
168
tutorial/Representation.html
Normal file
168
tutorial/Representation.html
Normal file
@ -0,0 +1,168 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Representation - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/Representation.html" />
|
||||
<meta name="description" content="The underlying memory representation of a Better Enum,
|
||||
including size and alignment." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/8-representation.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Representation</h2>
|
||||
<p>Let's go over some of the low-level properties of a Better Enum. This time, we
|
||||
will declare a more unusual enum than the ones we have seen.</p>
|
||||
<pre>#include <cassert>
|
||||
#include <iostream>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>ContentType</em>, <em>short</em>,
|
||||
<em>CompressedVideo</em> = <em>5</em>, <em>PCM</em> = <em>8</em>, <em>Subtitles</em> = <em>17</em>, <em>Comment</em> = <em>44</em>)</pre><p>This is for a hypothetical multimedia container file format. Perhaps the files
|
||||
have sections, and each one has a header:</p>
|
||||
<pre><em>struct Header</em> {
|
||||
<em>ContentType type</em>;
|
||||
short flags;
|
||||
int offset;
|
||||
};</pre><hr>
|
||||
<p>Here is what we have.</p>
|
||||
<pre>int main()
|
||||
{
|
||||
assert(<em>sizeof(ContentType)</em> == <em>2</em>);</pre><p><code>ContentType</code> behaves just like a <code>short</code><sup class="footnote-ref" id="fnref-*"><a href="#fn-*" rel="footnote">1</a></sup>, in fact it simply wraps one. This
|
||||
makes it possible to lay out structures in a predictable fashion:</p>
|
||||
<pre> Header <em>header</em> = {ContentType::PCM, 0, 0};
|
||||
|
||||
assert(<em>sizeof(header)</em> == <em>8</em>);
|
||||
assert((size_t)&<em>header.flags -</em> (size_t)&<em>header.type</em> == <em>2</em>);</pre><hr>
|
||||
<p><code>uint16_t</code> is called <code>ContentType</code>'s <em>underlying</em> or <em>representation</em> type. If
|
||||
you want to know the representation type of any enum you have declared, it is
|
||||
available as the member type <code>::_integral</code>:</p>
|
||||
<pre> <em>ContentType::_integral</em> untrusted_value = 44;</pre><p>Use this if you want a sized field to receive untrusted data, but aren't willing
|
||||
to call it <code>ContentType</code> yet because you have not validated it. Your validator
|
||||
will likely call <code>::_from_integral_nothrow</code>, perform any other validation your
|
||||
application requires, and then return <code>ContentType</code>.</p>
|
||||
<pre> ContentType type =
|
||||
ContentType::_from_integral(untrusted_value);
|
||||
std::cout << type._to_string() << std::endl;</pre><hr>
|
||||
<p>You have probably noticed the initializers on each of the constants in
|
||||
<code>ContentType</code>. This allows you to declare sparse enums for compatibility with
|
||||
external protocols or previous versions of your software. The initializers don't
|
||||
need to be literal integers — they can be anything that the compiler would
|
||||
accept in a normal <code>enum</code> declaration. If there was a macro called
|
||||
<code>BIG_FAT_MACRO</code> declared above, we could have written
|
||||
<code>Subtitles = BIG_FAT_MACRO</code>. We could also have written
|
||||
<code>Subtitles = CompressedVideo</code>.</p>
|
||||
<hr>
|
||||
<p>The in-memory representation of an enum value is simply the number it has been
|
||||
assigned by the compiler. You should be safe passing enums to functions like
|
||||
<code>fread</code> and <code>fwrite</code>, and casting memory blocks known to be safe to <code>struct</code>
|
||||
types containg enums. The enums will behave as expected.</p>
|
||||
<hr>
|
||||
<pre> return 0;
|
||||
}</pre><div class="footnotes">
|
||||
<hr>
|
||||
<ol><li id="fn-*"><p>It should properly be a <code>uint16_t</code>, and the rest of the header fields
|
||||
should also be explicitly sized. However, this code is trying to be
|
||||
compatible with <span class="cpp">C++</span><span class="eleven">98</span>, where those names aren't available in a portable
|
||||
manner.<a href="#fnref-*" rev="footnote">↩</a></p></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/CompileTimeUsage.html">Compile-time usage</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
134
tutorial/SafeSwitch.html
Normal file
134
tutorial/SafeSwitch.html
Normal file
@ -0,0 +1,134 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Safe switch - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/SafeSwitch.html" />
|
||||
<meta name="description" content="Better Enums can be used directly in switch statements like
|
||||
normal enums, making it possible for the compiler to check that all cases are
|
||||
listed, increasing the safety of your code." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/4-switch.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Safe switch</h2>
|
||||
<p>A Better Enum can be used directly in a <code>switch</code> statement:</p>
|
||||
<pre>#include <iostream>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
Channel channel = Channel::Green;
|
||||
int n;
|
||||
|
||||
<em>switch </em>(<em>channel</em>) {
|
||||
<em>case Channel::Red</em>: n = 13; break;
|
||||
<em>case Channel::Green</em>: n = 37; break;
|
||||
<em>case Channel::Blue</em>: n = 42; break;
|
||||
}</pre><p>If you miss a case or add a redundant one, your compiler should be able to give
|
||||
you a warning — try it!</p>
|
||||
<p>Note that on msvc, you may need to enable <a href="https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4062">warning C4062</a>.</p>
|
||||
<hr>
|
||||
<pre> std::cout << n << std::endl;
|
||||
return 0;
|
||||
}</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/Maps.html">Maps</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
155
tutorial/ScopeAndSafety.html
Normal file
155
tutorial/ScopeAndSafety.html
Normal file
@ -0,0 +1,155 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Scope and safety - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/ScopeAndSafety.html" />
|
||||
<meta name="description" content="Better Enums type safety features and limitations." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/7-safety.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Scope and safety</h2>
|
||||
<p>This tutorial shows some of the safety features of Better Enums: scope, how to
|
||||
control conversions, and the lack of a default constructor.</p>
|
||||
<p>On balance, Better Enums are in one way less type-safe than enum class, and in
|
||||
another way more type-safe. The first difference in safety is the presence of
|
||||
implicit conversion to integral types. The second difference is the lack of a
|
||||
default constructor. Both of these can be toggled, so you can make Better Enums
|
||||
strictly safer than enum class, or just as safe.</p>
|
||||
<p><a id="contents"></a><h3 class="contents">Contents</h3><ul class="contents"><li><a href="#Scope">Scope</a></li><li><a href="#ImplicitConversion">Implicit conversion</a></li><li><a href="#DefaultConstructor">Default constructor</a></li></ul></p>
|
||||
<a id="Scope"></a><h3>Scope</h3>
|
||||
<p>You have probably noticed by now that Better Enums are scoped: when you declare</p>
|
||||
<pre>#include <cassert>
|
||||
<em>#include <enum.h></em>
|
||||
|
||||
<em>BETTER_ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)</pre><p>you don't get names such as <code>Red</code> in the global namespace. Instead, you get
|
||||
<code>Channel</code>, and <code>Red</code> is accessible as <code>Channel::Red</code>. This is no big deal in
|
||||
<span class="cpp">C++</span><span class="eleven">11</span>, which has <code>enum class</code>. In <span class="cpp">C++</span><span class="eleven">98</span>, however, this typically requires
|
||||
effort. Better Enums brings scope uniformly to both variants. So, despite the
|
||||
above declaration, you can safely declare</p>
|
||||
<pre><em>BETTER_ENUM</em>(<em>Node</em>, <em>char</em>, <em>Red</em>, <em>Black</em>)</pre><p>and everything will work as expected.</p>
|
||||
<pre>int main()
|
||||
{
|
||||
assert((+<em>Channel::Red</em>)._to_integral() <em>!=</em> (+<em>Node::Red</em>)._to_integral());</pre><a id="ImplicitConversion"></a><h3>Implicit conversion</h3>
|
||||
<p>A major complaint in <span class="cpp">C++</span><span class="eleven">98</span> is that <code>enums</code> are implicitly convertible to
|
||||
integers. Unfortunately, that is also true of Better Enums, and I haven't found
|
||||
a way to forbid the conversions and still have switch case checking.</p>
|
||||
<p>Better Enums can be made as safe as <code>enum class</code> in <span class="cpp">C++</span><span class="eleven">11</span>, however. If your
|
||||
compiler supports <code>enum class</code> and you define
|
||||
<code>BETTER_ENUMS_STRICT_CONVERSION</code> before including <code>enum.h</code>, the following code
|
||||
will not compile:</p>
|
||||
<pre class="comment"> Channel channel = Channel::Red;
|
||||
int n = channel;</pre><p>The reason this is not enabled by default is explained in the reference page on
|
||||
<a href="../OptInFeatures.html#StrictConversions">strict conversions</a>.</p>
|
||||
<p>You can conveniently define the macro on your compiler's command line, or by
|
||||
creating a little header file that defines it, and then includes
|
||||
<code>enum.h</code>. You can then include this new header file in your project
|
||||
everywhere where you would have included <code>enum.h</code>.</p>
|
||||
<a id="DefaultConstructor"></a><h3>Default constructor</h3>
|
||||
<p>Better Enums generate without a default constructor. The purpose is to support
|
||||
the convention where if a Better Enum exists, then it has a valid value. So, if
|
||||
you uncomment this code, the program won't compile:</p>
|
||||
<pre class="comment"> Channel channel;</pre><p>If this is too strict for your project, you can relax it as described
|
||||
<a href="../OptInFeatures.html#DefaultConstructors">here</a>.</p>
|
||||
<hr>
|
||||
<pre> return 0;
|
||||
}</pre>
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/Representation.html">Representation</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
131
tutorial/StreamOperators.html
Normal file
131
tutorial/StreamOperators.html
Normal file
@ -0,0 +1,131 @@
|
||||
<!-- Generated automatically - edit the templates! -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Stream operators - Better Enums</title>
|
||||
|
||||
<link rel="canonical" href="http://aantron.github.io/better-enums/tutorial/StreamOperators.html" />
|
||||
<meta name="description" content="Using Better Enums with stream input and output operators." />
|
||||
<meta name="author" content="Anton Bachin" />
|
||||
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="stylesheet" href="../better-enums.css" />
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62962513-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a class="first" href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download</a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
<a href="../index.html">Home</a>
|
||||
<a href="../tutorial/HelloWorld.html">Tutorial</a>
|
||||
<a href="../ApiReference.html">Reference</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="spacer"> </div>
|
||||
|
||||
<header>
|
||||
<div class="container">
|
||||
<section>
|
||||
<h1><a href="../index.html">Better Enums</a></h1>
|
||||
<h2>Reflective compile-time enums for <span class="cpp">C++</span></h2>
|
||||
<h3>Open-source under the BSD license</h3>
|
||||
</section>
|
||||
|
||||
<section class="notes">
|
||||
<p>Version 0.11.3</p>
|
||||
<p>To install, just add <code>enum.h</code> to your project.</p>
|
||||
<p>
|
||||
Visit the GitHub repo for issues, feedback, and the latest development.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<a href="https://raw.githubusercontent.com/aantron/better-enums/0.11.3/enum.h"
|
||||
download>Download <code>enum.h</code></a>
|
||||
<a href="https://github.com/aantron/better-enums">GitHub</a>
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<p>
|
||||
Welcome to the Better Enums tutorials! The code in this tutorial forms a
|
||||
valid program, which you can <a href="https://github.com/aantron/better-enums/blob/0.11.3/example/6-iostreams.cc">download</a> and play with. The
|
||||
program runs as part of the automated test suite.
|
||||
</p>
|
||||
|
||||
<h2>Stream operators</h2>
|
||||
<p>These work <em>almost</em> as you'd expect. First, make sure you include <code>iostream</code>
|
||||
before <code>enum.h</code> in any translation unit in which you intend to use the
|
||||
operators:</p>
|
||||
<pre>#include <iostream>
|
||||
#include <enum.h>
|
||||
|
||||
<em>BETTER_ENUM(Channel, int, Red, Green, Blue)</em>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << <em>+Channel::Red</em> << std::endl;
|
||||
return 0;
|
||||
}</pre><p>The thing to watch for is the <code>+</code>: without it, <code>Channel::Red</code> is a value of type
|
||||
<code>Channel::_enumerated</code>, a <span class="cpp">C++</span><span class="eleven">98</span> enum type, so writing that to <code>cout</code> will
|
||||
output an integer. <code>+Channel::Red</code>, however, is a value of type <code>Channel</code>, and
|
||||
writing <em>that</em> instead will output the string <code>"Red"</code>.</p>
|
||||
<p>Input is also supported:</p>
|
||||
<pre class="comment">Channel channel = Channel::Blue;
|
||||
std::cin >> channel; // Expects input such as "Green".</pre><hr>
|
||||
<p>Only <code>char</code> streams are supported for the time being.</p>
|
||||
|
||||
|
||||
<section class="tutorial-footer">
|
||||
<p class="next">
|
||||
Continue to the next tutorial: <a href="../tutorial/ScopeAndSafety.html">Scope and safety</a>
|
||||
</p>
|
||||
|
||||
<p class="up">
|
||||
Or, return to the
|
||||
<a href="../index.html#Tutorial">tutorial index</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
||||
license. See
|
||||
<a href="https://github.com/aantron/better-enums/blob/0.11.3/doc/LICENSE">
|
||||
LICENSE</a>.
|
||||
<br />
|
||||
This page is part of the documentation for Better Enums 0.11.3.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user