Simple implementation of N4428 enum reflection.

This commit is contained in:
Anton Bachin 2015-07-09 17:26:10 -05:00
parent b182e16ec3
commit f1a0b5d0e4
7 changed files with 189 additions and 3 deletions

View File

@ -0,0 +1,74 @@
## C++17 reflection
Better Enums can be used to approximately implement the enums portion of the
[$cxx17 reflection proposal N4428][n4428] in $cxx11. The implementation is
*approximate* in the following senses:
- It only applies to Better Enums, not built-in enums.
- `enum_traits<E>::enumerators::get<I>::identifier` is a non-`constexpr`
function rather than a `constexpr` variable. I could make it a `constexpr`
variable as in the proposal, but that requires
[compile-time name trimming][slow-enum] to be enabled for the Better Enum
on which `get` 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.
- The return type of `identifier` is `const char*` instead of the proposed
`std::string_literal`, 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.
With that out of the way, we can look at a simple example.
[n4428]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
[slow-enum]: ${prefix}OptInFeatures.html#CompileTimeNameTrimming
---
The implementation is defined in [`extra/better-enums/n4428.h`][header]. Let's
assume that `extra/` has been added as a directory to search for include files.
#include <iostream>
<em>#include</em> <<em>enum.h</em>>
<em>#include</em> <<em>better-enums/n4428.h</em>>
[header]: https://github.com/aantron/better-enums/blob/$ref/extra/better-enums/n4428.h
---
Let's declare an enum:
<em>ENUM</em>(<em>Channel</em>, <em>char</em>, <em>Red</em> = <em>1</em>, <em>Green</em>, <em>Blue</em>)
N4428 proposes three `constexpr` traits, of which we have two implemented
exactly &mdash; that is, as `constexpr`:
<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>;
Let's check the results:
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>, "");
Finally, we can try using `identifier`:
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;
}
That prints `Blue`, as you would expect.
%% description = Approximate implementation of N4428 enum reflection based on
Better Enums.

1
doc/template/cxx17.tmpl vendored Normal file
View File

@ -0,0 +1 @@
<span class="cpp">C++</span><span class="eleven">17</span>

View File

@ -1 +1 @@
0.10.1 master

View File

@ -0,0 +1,62 @@
// This file was generated automatically.
// C++17 reflection
//
// Better Enums can be used to approximately implement the enums portion of the
// C++17 reflection proposal N4428 in C++11. The implementation is approximate
// in the following senses:
//
// 1. It only applies to Better Enums, not built-in enums.
// 2. enum_traits<E>::enumerators::get<I>::identifier is a non-constexpr
// function rather than a constexpr variable. I could make it a constexpr
// variable as in the proposal, but that requires compile-time name
// trimming to be enabled for the Better Enum on which get 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.
// 3. The return type of identifier is const char* instead of the proposed
// std::string_literal, 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.
//
// With that out of the way, we can look at an example.
// The implementation is defined in extra/better-enums/n4428.h. Let's assume
// that extra/ has been added as an include file path.
#include <iostream>
#include <enum.h>
#include <better-enums/n4428.h>
// Let's declare an enum:
ENUM(Channel, char, Red = 1, Green, Blue)
// N4428 requires three constexpr traits, of which we have two implemented
// exactly, that is, as constexpr:
constexpr std::size_t size =
std::enum_traits<Channel>::enumerators::size;
constexpr Channel value_0 =
std::enum_traits<Channel>::enumerators::get<0>::value;
constexpr Channel value_1 =
std::enum_traits<Channel>::enumerators::get<1>::value;
// Let's check the results:
static_assert(size == 3, "");
static_assert(value_0 == +Channel::Red, "");
static_assert(value_1 == +Channel::Green, "");
// Finally, we can try using identifier:
int main()
{
std::cout
<< std::enum_traits<Channel>::enumerators::get<2>::identifier()
<< std::endl;
return 0;
}

View File

@ -0,0 +1,46 @@
// This file is part of Better Enums, released under the BSD 2-clause license.
// See doc/LICENSE for details, or visit http://github.com/aantron/better-enums.
// This file provides an implementation of the enum reflection interface
// proposed in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4428.pdf
// over Better Enums.
// See further discussion and a demonstration of usage at
// example/107-c++17-reflection.cc, or visit:
// http://aantron.github.io/better-enums/demo/C++17Reflection.html
#pragma once
#ifndef BETTER_ENUMS__N4428_H
#define BETTER_ENUMS__N4428_H
namespace std {
template <typename Enum>
struct enum_traits {
struct enumerators {
constexpr static const size_t size = Enum::_size();
template <size_t Index>
struct get {
constexpr static Enum value = Enum::_values()[Index];
// In the proposal, this is a constexpr variable of type
// string_literal. It is possible to declare "identifier" that way
// with Better Enums, but only for enums that have compile-time name
// trimming enabled. Since compile-time name trimming currently has
// a severe performance impact, and is disabled by default, I chose
// to implement "identifier" as a function.
static const char* identifier() { return Enum::_names()[Index]; };
};
};
};
}
#endif // #ifndef BETTER_ENUMS__N4428_H

View File

@ -89,10 +89,11 @@ endforeach(TEST)
set(EXAMPLES set(EXAMPLES
1-hello-world 2-conversions 3-iterate 4-switch 5-iostreams 6-safety 1-hello-world 2-conversions 3-iterate 4-switch 5-iostreams 6-safety
7-representation 8-constexpr 101-special-values 102-any-underlying 7-representation 8-constexpr 101-special-values 102-any-underlying
103-bitset 104-quine) 103-bitset 104-quine 105-c++17-reflection)
set(SKIPPED_FOR_CXX98 set(SKIPPED_FOR_CXX98
8-constexpr 101-special-values 102-any-underlying 103-bitset 104-quine) 8-constexpr 101-special-values 102-any-underlying 103-bitset 104-quine
105-c++17-reflection)
set(SKIPPED_FOR_STRICT_CONVERSION 4-switch 102-any-underlying) set(SKIPPED_FOR_STRICT_CONVERSION 4-switch 102-any-underlying)
@ -112,6 +113,7 @@ endforeach(EXAMPLE)
# Add compiler flags. # Add compiler flags.
include_directories(..) include_directories(..)
include_directories(../extra)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)

View File

@ -0,0 +1 @@
Blue