diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 06571693286..a61bc7583ca 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -491,6 +491,12 @@ class CppGenerator : public BaseGenerator { } } + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { + // Declare EnumTraits as a template class + code_ += "template struct EnumTraits;"; + code_ += ""; + } + // Generate forward declarations for all equal operators if (opts_.generate_object_based_api && opts_.gen_compare) { for (const auto &struct_def : parser_.structs_.vec) { @@ -571,6 +577,16 @@ class CppGenerator : public BaseGenerator { } } + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { + // Generate traits for enums. + for (const auto &enum_def : parser_.enums_.vec) { + if (!enum_def->generated) { + SetNameSpace(enum_def->defined_namespace); + GenEnumTraits(*enum_def); + } + } + } + // Generate convenient global helper functions: if (parser_.root_struct_def_) { auto &struct_def = *parser_.root_struct_def_; @@ -1370,6 +1386,29 @@ class CppGenerator : public BaseGenerator { } } + void GenEnumTraits(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + + code_ += "template<>"; + code_ += "struct EnumTraits<{{ENUM_NAME}}> {"; + if (opts_.mini_reflect != IDLOptions::kNone) { + code_ += " constexpr static auto type_table = {{ENUM_NAME}}TypeTable;"; + } + code_ += " constexpr static auto name = EnumName{{ENUM_NAME}};"; + code_ += "};"; + code_ += ""; + + code_ += "inline EnumTraits<{{ENUM_NAME}}> EnumValTraits({{ENUM_NAME}}) {"; + code_ += " return EnumTraits<{{ENUM_NAME}}>{};"; + code_ += "}"; + code_ += ""; + + code_ += "inline const char *GetEnumName({{ENUM_NAME}} e) {"; + code_ += " return EnumValTraits(e).name(e);"; + code_ += "}"; + code_ += ""; + } + // Generate a union type and a trait type for it. void GenEnumObjectBasedAPI(const EnumDef &enum_def) { if (!(opts_.generate_object_based_api && enum_def.is_union)) { return; } diff --git a/tests/cpp17/generated_cpp17/monster_test_generated.h b/tests/cpp17/generated_cpp17/monster_test_generated.h index 1e11e222633..b56809789b1 100644 --- a/tests/cpp17/generated_cpp17/monster_test_generated.h +++ b/tests/cpp17/generated_cpp17/monster_test_generated.h @@ -61,6 +61,8 @@ struct TypeAliases; struct TypeAliasesBuilder; struct TypeAliasesT; +template struct EnumTraits; + } // namespace Example inline const ::flatbuffers::TypeTable *InParentNamespaceTypeTable(); @@ -4211,6 +4213,90 @@ inline const ::flatbuffers::TypeTable *TypeAliasesTypeTable() { return &tt; } +template<> +struct EnumTraits { + constexpr static auto type_table = ColorTypeTable; + constexpr static auto name = EnumNameColor; +}; + +inline EnumTraits EnumValTraits(Color) { + return EnumTraits{}; +} + +inline const char *GetEnumName(Color e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = RaceTypeTable; + constexpr static auto name = EnumNameRace; +}; + +inline EnumTraits EnumValTraits(Race) { + return EnumTraits{}; +} + +inline const char *GetEnumName(Race e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = LongEnumTypeTable; + constexpr static auto name = EnumNameLongEnum; +}; + +inline EnumTraits EnumValTraits(LongEnum) { + return EnumTraits{}; +} + +inline const char *GetEnumName(LongEnum e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = AnyTypeTable; + constexpr static auto name = EnumNameAny; +}; + +inline EnumTraits EnumValTraits(Any) { + return EnumTraits{}; +} + +inline const char *GetEnumName(Any e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = AnyUniqueAliasesTypeTable; + constexpr static auto name = EnumNameAnyUniqueAliases; +}; + +inline EnumTraits EnumValTraits(AnyUniqueAliases) { + return EnumTraits{}; +} + +inline const char *GetEnumName(AnyUniqueAliases e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = AnyAmbiguousAliasesTypeTable; + constexpr static auto name = EnumNameAnyAmbiguousAliases; +}; + +inline EnumTraits EnumValTraits(AnyAmbiguousAliases) { + return EnumTraits{}; +} + +inline const char *GetEnumName(AnyAmbiguousAliases e) { + return EnumValTraits(e).name(e); +} + inline const MyGame::Example::Monster *GetMonster(const void *buf) { return ::flatbuffers::GetRoot(buf); } diff --git a/tests/cpp17/generated_cpp17/optional_scalars_generated.h b/tests/cpp17/generated_cpp17/optional_scalars_generated.h index 75b8da3bfa8..7f64c801772 100644 --- a/tests/cpp17/generated_cpp17/optional_scalars_generated.h +++ b/tests/cpp17/generated_cpp17/optional_scalars_generated.h @@ -19,6 +19,8 @@ struct ScalarStuff; struct ScalarStuffBuilder; struct ScalarStuffT; +template struct EnumTraits; + inline const ::flatbuffers::TypeTable *ScalarStuffTypeTable(); enum class OptionalByte : int8_t { @@ -928,6 +930,20 @@ inline const ::flatbuffers::TypeTable *ScalarStuffTypeTable() { return &tt; } +template<> +struct EnumTraits { + constexpr static auto type_table = OptionalByteTypeTable; + constexpr static auto name = EnumNameOptionalByte; +}; + +inline EnumTraits EnumValTraits(OptionalByte) { + return EnumTraits{}; +} + +inline const char *GetEnumName(OptionalByte e) { + return EnumValTraits(e).name(e); +} + inline const optional_scalars::ScalarStuff *GetScalarStuff(const void *buf) { return ::flatbuffers::GetRoot(buf); } diff --git a/tests/cpp17/generated_cpp17/union_vector_generated.h b/tests/cpp17/generated_cpp17/union_vector_generated.h index e785ecda0d4..7c8377833ea 100644 --- a/tests/cpp17/generated_cpp17/union_vector_generated.h +++ b/tests/cpp17/generated_cpp17/union_vector_generated.h @@ -31,6 +31,8 @@ struct Movie; struct MovieBuilder; struct MovieT; +template struct EnumTraits; + inline const ::flatbuffers::TypeTable *AttackerTypeTable(); inline const ::flatbuffers::TypeTable *RapunzelTypeTable(); @@ -1196,6 +1198,34 @@ inline const ::flatbuffers::TypeTable *MovieTypeTable() { return &tt; } +template<> +struct EnumTraits { + constexpr static auto type_table = CharacterTypeTable; + constexpr static auto name = EnumNameCharacter; +}; + +inline EnumTraits EnumValTraits(Character) { + return EnumTraits{}; +} + +inline const char *GetEnumName(Character e) { + return EnumValTraits(e).name(e); +} + +template<> +struct EnumTraits { + constexpr static auto type_table = GadgetTypeTable; + constexpr static auto name = EnumNameGadget; +}; + +inline EnumTraits EnumValTraits(Gadget) { + return EnumTraits{}; +} + +inline const char *GetEnumName(Gadget e) { + return EnumValTraits(e).name(e); +} + inline const Movie *GetMovie(const void *buf) { return ::flatbuffers::GetRoot(buf); } diff --git a/tests/cpp17/stringify_util.h b/tests/cpp17/stringify_util.h index e2e7e2230b6..300cabb7419 100644 --- a/tests/cpp17/stringify_util.h +++ b/tests/cpp17/stringify_util.h @@ -150,11 +150,9 @@ std::optional StringifyFlatbufferValue(T &&val, return detail::StringifyArithmeticType(static_cast(val)); } - // Is it an enum? If so, print it like an int, since Flatbuffers doesn't yet - // have type-based reflection for enums, so we can't print the enum's name :( + // Is it an enum? If so, print the enum's name without quotes. else if constexpr (std::is_enum_v) { - return StringifyFlatbufferValue( - static_cast>(val), indent); + return GetEnumName(val); } // Is it an int, double, float, uint32_t, etc.? diff --git a/tests/cpp17/test_cpp17.cpp b/tests/cpp17/test_cpp17.cpp index 6c1929120e3..2a233f904c5 100644 --- a/tests/cpp17/test_cpp17.cpp +++ b/tests/cpp17/test_cpp17.cpp @@ -111,7 +111,7 @@ void StringifyAnyFlatbuffersTypeTest() { y = 2.2 z = 3.3 test1 = 6.6 - test2 = 2 + test2 = Green test3 = MyGame.Example.Test{ a = 11 b = 90 @@ -126,8 +126,8 @@ void StringifyAnyFlatbuffersTypeTest() { 6, 7 ] - color = 8 - test_type = 0 + color = Blue + test_type = NONE testbool = 1 testhashs32_fnv1 = 4 testhashu32_fnv1 = 5 @@ -143,11 +143,11 @@ void StringifyAnyFlatbuffersTypeTest() { single_weak_reference = 15 co_owning_reference = 16 non_owning_reference = 17 - any_unique_type = 0 - any_ambiguous_type = 0 - signed_enum = -1 - long_enum_non_enum_default = 0 - long_enum_normal_default = 2 + any_unique_type = NONE + any_ambiguous_type = NONE + signed_enum = None + long_enum_non_enum_default = + long_enum_normal_default = LongOne nan_default = nan inf_default = inf positive_inf_default = inf