mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Added samples.
This commit is contained in:
parent
b887363abd
commit
a444bf349d
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
|
samples/*.exe
|
||||||
scratch/
|
scratch/
|
||||||
|
|||||||
89
samples/1-basic.cc
Normal file
89
samples/1-basic.cc
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Basic conversions to/from strings and the underlying integral type.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, uint8_t, Red, Green = 2, Blue, Alias = Red);
|
||||||
|
|
||||||
|
void print_channel(Channel channel)
|
||||||
|
{
|
||||||
|
std::cout
|
||||||
|
<< "channel \'"
|
||||||
|
<< channel.to_string()
|
||||||
|
<< "\' has value "
|
||||||
|
<< (int)channel.to_integral() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// A value must be assigned upon construction.
|
||||||
|
Channel channel = Channel::Green;
|
||||||
|
print_channel(channel);
|
||||||
|
|
||||||
|
// This will not work.
|
||||||
|
// Channel default_constructed_channel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Conversions from strings and the integral type. Function names are
|
||||||
|
// prefixed with _ to avoid conflicts with constant names. _from_integral is
|
||||||
|
// a checked cast.
|
||||||
|
channel = Channel::_from_integral(0);
|
||||||
|
print_channel(channel);
|
||||||
|
|
||||||
|
channel = Channel::_from_string("Blue");
|
||||||
|
print_channel(channel);
|
||||||
|
|
||||||
|
channel = Channel::_from_string_nocase("bluE");
|
||||||
|
print_channel(channel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Bad conversions.
|
||||||
|
try {
|
||||||
|
channel = Channel::_from_integral(15);
|
||||||
|
throw std::logic_error("expected an exception");
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error &e) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
channel = Channel::_from_string("Purple");
|
||||||
|
throw std::logic_error("expected an exception");
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error &e) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
channel = Channel::_from_string_nocase("bluee");
|
||||||
|
throw std::logic_error("expected an exception");
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error &e) { }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Unsafe unchecked cast.
|
||||||
|
channel = Channel::_from_integral_unchecked(2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Direct conversion of a constant unfortunately requires an explicit
|
||||||
|
// promotion.
|
||||||
|
std::cout << (+Channel::Green).to_string() << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The type name is available as a string.
|
||||||
|
std::cout << Channel::_name << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(sizeof(Channel) == sizeof(uint8_t),
|
||||||
|
"enum has the same size as its underlying integral type");
|
||||||
|
|
||||||
|
static_assert(alignof(Channel) == alignof(uint8_t),
|
||||||
|
"enum has the same alignment as its underlying integral type");
|
||||||
|
|
||||||
|
static_assert(std::is_same<Channel::_Integral, uint8_t>(),
|
||||||
|
"the underlying integral type is accessible as a member");
|
||||||
39
samples/2-iterate.cc
Normal file
39
samples/2-iterate.cc
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Range properties and iteration over all constants.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, int, Red = 3, Green = 4, Blue = 0);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Static range properties.
|
||||||
|
std::cout << "first: " << (+Channel::_first).to_string() << std::endl;
|
||||||
|
std::cout << "last: " << (+Channel::_last).to_string() << std::endl;
|
||||||
|
std::cout << "minimum: " << (+Channel::_min).to_string() << std::endl;
|
||||||
|
std::cout << "maximum: " << (+Channel::_max).to_string() << std::endl;
|
||||||
|
std::cout << "count: " << Channel::_size << std::endl;
|
||||||
|
std::cout << "span: " << Channel::_span << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Listing declared values.
|
||||||
|
for (Channel channel : Channel::_values)
|
||||||
|
std::cout << channel.to_integral() << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Listing declared names.
|
||||||
|
for (const char *name : Channel::_names)
|
||||||
|
std::cout << name << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Direct iterator usage.
|
||||||
|
std::cout
|
||||||
|
<< "first (using iterator): "
|
||||||
|
<< *Channel::_names.begin()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
samples/3-switch.cc
Normal file
38
samples/3-switch.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Switch case exhaustiveness checking.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, int, Red, Green, Blue);
|
||||||
|
|
||||||
|
void respond_to_channel(Channel channel)
|
||||||
|
{
|
||||||
|
// Try adding an extra case or removing one. Your compiler should issue a
|
||||||
|
// warning.
|
||||||
|
switch (channel) {
|
||||||
|
case Channel::Red:
|
||||||
|
std::cout << "red channel" << std::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel::Green:
|
||||||
|
std::cout << "green channel" << std::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel::Blue:
|
||||||
|
std::cout << "blue channel" << std::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// A redundant case.
|
||||||
|
// case 3:
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
respond_to_channel(Channel::Red);
|
||||||
|
respond_to_channel(Channel::Blue);
|
||||||
|
respond_to_channel(Channel::Green);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
92
samples/4-constexpr.cc
Normal file
92
samples/4-constexpr.cc
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Usage in constexpr expressions. All members of an ENUM are constexpr when
|
||||||
|
// given constant arguments, with the exception of _to_string and dereferencing
|
||||||
|
// the _names iterator.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, int, Red, Green, Blue);
|
||||||
|
|
||||||
|
// Initialization.
|
||||||
|
constexpr Channel channel_1 = Channel::Green;
|
||||||
|
|
||||||
|
constexpr Channel channel_4 = Channel::_from_integral(2);
|
||||||
|
|
||||||
|
constexpr Channel channel_2 = Channel::_from_string("Blue");
|
||||||
|
constexpr Channel channel_3 = Channel::_from_string_nocase("gReEn");
|
||||||
|
|
||||||
|
// Conversion to integer (but not to string).
|
||||||
|
constexpr int channel_1_representation = channel_1.to_integral();
|
||||||
|
|
||||||
|
// Validity checks (including against strings).
|
||||||
|
constexpr bool should_be_valid_1 = Channel::_is_valid(2);
|
||||||
|
constexpr bool should_be_invalid_1 = Channel::_is_valid(42);
|
||||||
|
|
||||||
|
constexpr bool should_be_valid_2 = Channel::_is_valid("Red");
|
||||||
|
constexpr bool should_be_invalid_2 = Channel::_is_valid("red");
|
||||||
|
|
||||||
|
constexpr bool should_be_valid_3 = Channel::_is_valid_nocase("red");
|
||||||
|
constexpr bool should_be_invalid_3 = Channel::_is_valid_nocase("reed");
|
||||||
|
|
||||||
|
// _names and _values collections and iterator creation.
|
||||||
|
constexpr Channel channel_5 = *Channel::_values.begin();
|
||||||
|
constexpr auto name_iterator = Channel::_names.begin();
|
||||||
|
|
||||||
|
// Range properties.
|
||||||
|
constexpr Channel channel_6 = Channel::_max;
|
||||||
|
constexpr size_t span = Channel::_span;
|
||||||
|
|
||||||
|
// Type name.
|
||||||
|
constexpr auto name = Channel::_name;
|
||||||
|
|
||||||
|
// Explicit promotion.
|
||||||
|
constexpr int converted = (+Channel::Green).to_integral();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The above, printed for verification.
|
||||||
|
void print_channel(int number, Channel channel)
|
||||||
|
{
|
||||||
|
std::cout
|
||||||
|
<< "channel_"
|
||||||
|
<< number
|
||||||
|
<< " is "
|
||||||
|
<< channel.to_string()
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRINT(n) print_channel(n, channel_ ## n)
|
||||||
|
|
||||||
|
void print_validity(bool expected, bool actual)
|
||||||
|
{
|
||||||
|
std::cout
|
||||||
|
<< "should be "
|
||||||
|
<< expected
|
||||||
|
<< ": "
|
||||||
|
<< actual
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
PRINT(1);
|
||||||
|
PRINT(2);
|
||||||
|
PRINT(3);
|
||||||
|
PRINT(4);
|
||||||
|
|
||||||
|
print_validity(true, should_be_valid_1);
|
||||||
|
print_validity(false, should_be_invalid_1);
|
||||||
|
print_validity(true, should_be_valid_2);
|
||||||
|
print_validity(false, should_be_invalid_2);
|
||||||
|
print_validity(true, should_be_valid_3);
|
||||||
|
print_validity(false, should_be_invalid_3);
|
||||||
|
|
||||||
|
PRINT(5);
|
||||||
|
PRINT(6);
|
||||||
|
|
||||||
|
std::cout << *name_iterator << std::endl;
|
||||||
|
std::cout << "span: " << span << std::endl;
|
||||||
|
std::cout << "type name: " << name << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
62
samples/5-containers.cc
Normal file
62
samples/5-containers.cc
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Usage with STL containers.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, int, Red, Green, Blue);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Vectors.
|
||||||
|
std::vector<Channel> vector = {Channel::Red, Channel::Green};
|
||||||
|
|
||||||
|
vector.push_back(Channel::Red);
|
||||||
|
vector.push_back(Channel::Blue);
|
||||||
|
vector.push_back(Channel::Blue);
|
||||||
|
vector.push_back(Channel::Red);
|
||||||
|
|
||||||
|
for (Channel channel : vector)
|
||||||
|
std::cout << channel.to_string() << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Maps. Lack of a default constructor in the current version means that
|
||||||
|
// std::map::operator[] usage is complicated. Insertion can still be done
|
||||||
|
// with ::insert, and access with ::find.
|
||||||
|
std::map<const char*, Channel> map = {{"first", Channel::Blue}};
|
||||||
|
map.insert({"second", Channel::Green});
|
||||||
|
|
||||||
|
for (Channel channel : Channel::_values)
|
||||||
|
map.insert({channel.to_string(), channel});
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (auto item : map) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
std::cout << ", ";
|
||||||
|
|
||||||
|
std::cout
|
||||||
|
<< item.first
|
||||||
|
<< " -> "
|
||||||
|
<< item.second.to_string();
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// As map keys.
|
||||||
|
std::map<Channel, const char*> descriptions =
|
||||||
|
{{Channel::Red, "the red channel"},
|
||||||
|
{Channel::Green, "the green channel"},
|
||||||
|
{Channel::Blue, "the blue channel"}};
|
||||||
|
|
||||||
|
for (auto item : descriptions)
|
||||||
|
std::cout << item.second << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
27
samples/Makefile
Normal file
27
samples/Makefile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
SOURCES := $(wildcard *.cc)
|
||||||
|
BINARIES := $(SOURCES:.cc=.exe)
|
||||||
|
|
||||||
|
CXX := c++
|
||||||
|
CXXFLAGS := -std=c++11 -Wall -I ..
|
||||||
|
|
||||||
|
.PHONY : default
|
||||||
|
default : run
|
||||||
|
@:
|
||||||
|
|
||||||
|
.PHONY : all
|
||||||
|
all : $(BINARIES)
|
||||||
|
|
||||||
|
%.exe : %.cc ../*.h Makefile
|
||||||
|
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
.PHONY : clean
|
||||||
|
clean :
|
||||||
|
rm -rf *.exe
|
||||||
|
|
||||||
|
.PHONY : run
|
||||||
|
run : all
|
||||||
|
@for BINARY in $(BINARIES) ; \
|
||||||
|
do \
|
||||||
|
echo ./$$BINARY ; \
|
||||||
|
./$$BINARY | sed -e "s/^/ /" ; \
|
||||||
|
done
|
||||||
Loading…
x
Reference in New Issue
Block a user