Вот действующий код.
Хоть он на 20, простейшими define’ами (consteval → constexpr, constinit → пустота) можно собрать его и на 17.
#include <iostream>
#include <array>
#include <string>
enum class FromRawMem { INST };
enum class NoValue { INST };
#define consteval constexpr
class Char4
{
public:
using CppArray = std::array<char, 4>;
constexpr explicit Char4(NoValue) : fBuf { { 0, 0, 0, 0 } } {}
consteval Char4(const char (&x)[5]) : fBuf { { x[0], x[1], x[2], x[3] } } {}
constexpr Char4(const Char4&) = default;
Char4(FromRawMem, const char* data) { fBuf.asInt = *reinterpret_cast<const uint32_t*>(data); }
constexpr const CppArray& toAr() const { return fBuf.asAr; }
CppArray& toAr () { return fBuf.asAr; }
constexpr std::string_view toSv() const { return { fBuf.asAr.data(), 4 }; }
/// @return byte-order dependent integer value
/// @warning
/// DO NOT save toRawInt() as Intel, Motorola or any numeral system (decimal etc).
/// You MAY save it as raw memory, or use it for optimization.
constexpr uint32_t toRawInt() const { return fBuf.asInt; }
constexpr const char* data() const { return fBuf.asAr.data(); }
private:
union {
std::array<char, 4> asAr;
uint32_t asInt;
} fBuf;
};
constexpr inline bool operator == (Char4 x, Char4 y) { return x.toRawInt() == y.toRawInt(); }
constexpr inline bool operator != (Char4 x, Char4 y) { return x.toRawInt() != y.toRawInt(); }
constexpr inline bool operator == (Char4 x, std::string_view y)
{ return y.size() == 4 && x.toRawInt() == *reinterpret_cast<const uint32_t*>(y.data()); }
constexpr inline bool operator != (Char4 x, std::string_view y)
{ return !operator == (x, y); }
constexpr inline bool operator == (std::string_view x, Char4 y)
{ return operator == (y, x); }
constexpr inline bool operator != (std::string_view x, Char4 y)
{ return !operator == (y, x); }
/// Size of enum class, no generic implementation.
template <class Ec>
constexpr size_t enumSize();
namespace detail {
/// Jut does not compile if arguments contain assignments
constexpr int enumDummy(...) { return 0; }
template <typename T, std::size_t...Is>
consteval std::array<T, sizeof...(Is)>
make_array(const T& value, std::index_sequence<Is...>)
{
return {{(static_cast<void>(Is), value)...}};
}
template <std::size_t N, typename T>
consteval std::array<T, N> make_array(const T& value)
{
return make_array(value, std::make_index_sequence<N>());
}
}
#define DEFINE_ENUM_SIZE(Name) \
template <> constexpr size_t enumSize<Name>() { return static_cast<int>(Name::NN); }
#define DEFINE_ENUM_N(Name, ...) \
enum class Name { __VA_ARGS__ }; \
template <> constexpr size_t enumSize<Name>() { \
enum Internal { __VA_ARGS__ , NNNNNN }; \
detail::enumDummy(__VA_ARGS__); \
return NNNNNN; }
enum class DummyElem { INST };
enum class IncompleteArray { INST };
enum class FillArray { INST };
enum class PairwiseTempInit {INST };
namespace detail {
namespace array {
template <auto K, class V>
class KeyValue {
public:
static constexpr auto index = K;
V && v;
consteval KeyValue(V && aV) : v(aV) {}
};
// checkOneForRepeat
template <class Ec>
consteval void checkOneForRepeat() {}
template <class Ec, Ec Only>
consteval void checkOneForRepeat() {}
template <class Ec, Ec First, Ec Second, Ec ... Rest>
consteval void checkOneForRepeat()
{
static_assert(First != Second, "Repeating array keys!");
checkOneForRepeat<Ec, First, Rest...>();
}
// checkForRepeat
template <class Ec>
consteval void checkForRepeat() {}
template <class Ec, Ec Only>
consteval void checkForRepeat() {}
template <class Ec, Ec First, Ec Second, Ec ... Rest>
consteval void checkForRepeat()
{
checkOneForRepeat<Ec, First, Second, Rest...>();
checkForRepeat<Ec, Second, Rest...>();
}
template <class Ec, Ec ... args>
consteval void checkKeys()
{
checkForRepeat<Ec, args...>();
}
}
}
template<auto K, class V>
consteval auto kv(V && v) { return detail::array::KeyValue<K, V>(v); }
template <class T, class Ec>
class EcArray
{
public:
static constexpr auto Size = enumSize<Ec>();
using CppArray = std::array<T, Size>;
using Elem = T;
using iterator = Elem*;
using const_iterator = const Elem*;
constexpr CppArray& toAr() { return fBuf; }
constexpr const CppArray& toAr() const { return fBuf; }
constexpr Elem* data() { return fBuf.data(); }
constexpr const Elem* data() const { return fBuf.data(); }
constexpr size_t size() const { return Size; }
constexpr iterator begin() { return fBuf.begin(); }
constexpr iterator end() { return fBuf.end(); }
constexpr const_iterator begin() const { return fBuf.begin(); }
constexpr const_iterator end() const { return fBuf.end(); }
constexpr const_iterator cbegin() const { return fBuf.begin(); }
constexpr const_iterator cend() const { return fBuf.end(); }
constexpr EcArray() = delete;
constexpr EcArray(NoValue) {}
constexpr EcArray(const EcArray&) = default;
constexpr EcArray(EcArray&&) = default;
EcArray& operator = (const EcArray&) = default;
EcArray& operator = (EcArray&&) = default;
template <class U>
constexpr EcArray(NoValue, const U&& x) : fBuf {x } {}
template <class ... Args>
consteval EcArray(Args&& ... x)
: fBuf { x... }
{ static_assert(sizeof...(Args) == Size, "EcArray size mismatch"); }
template <class U, Ec K, class V, class ... Args>
consteval EcArray(
PairwiseTempInit, U&& temp,
detail::array::KeyValue<K, V> first,
Args&& ... rest)
: fBuf { detail::make_array<Size, T>(temp) }
{
static_assert(sizeof...(Args) + 1 == Size, "EcArray pairwise size mismatch");
detail::array::checkKeys< Ec, K, (std::remove_reference_t<decltype(rest)>::index)... >();
initPairwise(first, rest...);
}
private:
CppArray fBuf;
consteval void initPairwise() {}
template <Ec K, class V, class ... Args>
consteval void initPairwise(
detail::array::KeyValue<K, V> first,
Args&& ... rest)
{
fBuf[static_cast<size_t>(K)] = T { first.v };
initPairwise(rest...);
}
};
DEFINE_ENUM_N( Letter, A, B, C )
extern const EcArray <Char4, Letter> names2;
//const EcArray <Char4, Letter> names { "alph", "brav", "char" };
constinit const EcArray <Char4, Letter> names2
{ PairwiseTempInit::INST, Char4 { NoValue::INST},
kv <Letter::A> ( "alp1" ),
kv <Letter::B> ( "bra1" ),
kv <Letter::C> ( "cha1" ) };
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}