#include<type_traits>
#include<cstdint>
#include<limits>
#include<functional>
struct Not_base {
constexpr Not_base() {}
template<typename T>
constexpr Not_base(T&& a) {} //just a place holder
};
template<typename T, typename Base= Not_base>
//Base must be another wrapper object
struct Enum_wrapper: Base {
using Enum_t=T;
Enum_t enumerator;
bool is_initialized;
using Base_t= Base;
constexpr Enum_wrapper() {}
constexpr Enum_wrapper(Enum_t a):
enumerator{a}, is_initialized{true} {}
template<typename Other_Enum_t>
requires(std::is_scoped_enum_v<Other_Enum_t>)
constexpr Enum_wrapper(Other_Enum_t a): Base{a}, enumerator{}, is_initialized{false} {}
//One could optionally (to make it even better) append/add:
/*
using enum Enum_t;
using Base;
Or Anything equavulent to the two lines above
*/
};
template <typename Enum_wrapper, Enum_wrapper obj,template<typename T, T obj_nested> typename correct_enum>
consteval auto potential_base() {
using potential_base= typename Enum_wrapper::Base_t;
if constexpr (!obj.is_initialized) {
if constexpr (std::is_same_v<potential_base,Not_base>) {
static_assert(false, "not found");
return;
}
else {
return correct_enum<potential_base, potential_base{obj}> {};
}
}
else {
static_assert(false, "not found");
return;
}
}
template<typename Enum_wrapper, Enum_wrapper obj>
struct correct_enum {
using potential_base_t=
decltype(
potential_base<Enum_wrapper, obj, correct_enum>()
);
using enum_t=
std::conditional_t<
obj.is_initialized,
typename Enum_wrapper::Enum_t,
typename potential_base_t::enum_t
>;
static constexpr enum_t enum_v = obj.is_initialized ? obj.enumerator : potential_base_t::enum_v;
};
namespace {
template<typename T>
struct raw_object { //object in integer form (think of it like hexdump of an object)
unsigned char *data;
T obj_stored;
constexpr static std::size_t size_of_data= sizeof(T);
consteval raw_object(T a): obj_stored{a}, data{&obj_stored} {
//I know code is messy but didnt know a better way, sorry
}
consteval raw_object(raw_object& a): obj_stored{a.obj_stored},
data{&obj_stored} {
}
template<typename Op, typename T_2>
requires(std::is_arithmetic_v<T_2>)
consteval raw_object do_op(T_2 arg) {
raw_object temp{*this};
unsigned char carry=0;
for(std::size_t count=0; count!=size_of_data; count++) {
unsigned char result=Op{}(Op{}(temp[count], arg),carry);
if(result<temp) {
carry = 1;
}
else {
temp[count]= result;
break;
}
}
return temp;
}
template<typename T_2>
consteval raw_object operator+(T_2 obj){
return do_op<std::plus>(obj);
}
template<typename T_2>
consteval raw_object operator*(T_2 obj){
return do_op<std::multipies>(obj);
}
}
constexpr std::uintmax_t b= 10;//THE B IN logbN
template<template<std::uintmax_t, std::uintmax_t, signed, typename N_t_, N_t_, bool> class bc, std:uintmax_t instance, std::uintmax_t sub_instance, signed m, typename N_t, N_t N, bool s>
struct exist {
//million credits to
//https://www.lukas-barth.net/blog/checking-if-specialized/
//for saving me here:
template<typename exist_if_exist= decltype(std::declval<bc<instance, sub_instance, m, N_t, N,s>>().~bc<instance, sub_instance, m, N_t, N, s>())>
bool static does() {
return true;
}
bool static does() {
if(t==0){
bc<instance, sub_instance, m, N_t,N+1, s, t> dummy{};
}
return false;
}
};
template< std::uintmax_t instance,//instance is purely to avoid writing the same thing many times
std::uintmax_t obj_instance,//zero if you just want a number (in that case instance would be 0 or 1)
signed minus_by=0,
typename N_t= std::uintmax_t,
N_t N=0, bool search_or_asked= false>
struct sequential_count {
//will also be used to represent enumeurators now, hence tried to make this super efficient
template< std::uintmax_t multipy_by=1, std::uintmax_t b_= b>
consteval static N_t get_num() {
if(exist<sequential_count, instance, obj_instance, minus_by, N_t, (N*multipy_by), true>::template does<multipy_by, b_>()) {
if(exist<sequential_count, instance, obj_instance, minus_by, N_t, (N*multipy_by)-b_, true>::template does<multipy_by, b_>()) {
return sequential_count<instance, obj_instance, minus_by, N_t, N, true>::template get_num<1,2>();
}
else {
return sequential_count<instance, obj_instance, minus_by, N_t, (N*multipy_by*b), true, minus_by>::template get_num< multipy_by*b, b_>();
}
}
else {
return N-minus_by;
}
}
};
}
template<typename intermediate_enum_wrapper, std::uintmax_t N= sequential_count<0, 0>::get_num()>
struct Enum_wrapper_complete {
Enum_wrapper_complete(intermediate_enum_wrapper a) {
sequential_count<2+N, sequential_count::get_num<1, 0>(), raw_object<a>, a, true> {}; // explicit initliazation to actually sign in a value.
};
consteval operator typename correct_enum<intermediate_enum_wrapper,
object_list<intermediate_enum_wrapper, >::enum_t()
{
return sequential_count<2+N, sequential_count::get_num<1, 0, 1>()>::get_num().obj_stored;
}
};
int main()
{
enum class A { voilet, blue, roses, red};
constexpr A enum_obj= A::blue;
Enum_wrapper B{enum_obj};
Enum_wrapper_complete wrap{B};
return 0;
}