mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Simple implementation of N4428 enum reflection.
This commit is contained in:
parent
b182e16ec3
commit
f1a0b5d0e4
74
doc/demo/105-c++17-reflection.md
Normal file
74
doc/demo/105-c++17-reflection.md
Normal 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 — 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
1
doc/template/cxx17.tmpl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<span class="cpp">C++</span><span class="eleven">17</span>
|
||||||
2
doc/template/ref.tmpl
vendored
2
doc/template/ref.tmpl
vendored
@ -1 +1 @@
|
|||||||
0.10.1
|
master
|
||||||
62
example/105-c++17-reflection.cc
Normal file
62
example/105-c++17-reflection.cc
Normal 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;
|
||||||
|
}
|
||||||
46
extra/better-enums/n4428.h
Normal file
46
extra/better-enums/n4428.h
Normal 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
|
||||||
@ -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)
|
||||||
|
|||||||
1
test/expect/105-c++17-reflection
Normal file
1
test/expect/105-c++17-reflection
Normal file
@ -0,0 +1 @@
|
|||||||
|
Blue
|
||||||
Loading…
x
Reference in New Issue
Block a user