Commit a5d9d0f7 authored by David P. Sicilia's avatar David P. Sicilia Committed by Wouter van Oortmerssen

[C++17] Add Traits class for Tables and Factory function within it. (#5678)

* Include flattests_cpp17 in unit tests when C++17 build is enabled.

* [C++17] Generate generic table factory function.

1. For each table, generate a convenient free-standing factory
   function that allows creating the table in a generic way by
   specifying only the type.  This is the first change in a series
   of changes to make Flatbuffers generated C++ code more friendly
   to code bases that make use of C++ template metaprogramming
   techniques to manage the serialization process.  Example:

     Before :(

       // The name of the Flatbuffers type (and namespace) must
       // be hard-coded when writing the factory function.
       auto monster = MyGame::Example::CreateMonster(fbb, ...);

     After  :)

       using type_to_create = MyGame::Example::Monster;
       // No namespace needed on CreateByTagType.
       auto monster = CreateByTagType((type_to_create*)nullptr,
                                      fbb, ...);

   This feature requires building with C++14 or greater, and thus
   it is guarded behind --cpp-std >= c++17 in the flatbuffers C++
   generator.

2. Fix a CMake bug to include C++17 unit tests in test suite.

* [C++17] Replace standalone variadic factory function with type_traits.

Add a `type_traits` to each table class.  This `type_traits` can be
populated with various compile-time info about the table.  Initially,
we have the Create* function and type, but is extensible in the future.

* Remove empty line and fix stale comments.

* Rename type_traits to Traits and move fwd declaration.

* Fix parameter evaluation order issue and use lambda for scope.
parent 3cd9b643
...@@ -530,6 +530,9 @@ if(FLATBUFFERS_BUILD_TESTS) ...@@ -530,6 +530,9 @@ if(FLATBUFFERS_BUILD_TESTS)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION
"${CMAKE_CURRENT_BINARY_DIR}") "${CMAKE_CURRENT_BINARY_DIR}")
add_test(NAME flattests COMMAND flattests) add_test(NAME flattests COMMAND flattests)
if(FLATBUFFERS_BUILD_CPP17)
add_test(NAME flattests_cpp17 COMMAND flattests_cpp17)
endif()
if(FLATBUFFERS_BUILD_GRPCTEST) if(FLATBUFFERS_BUILD_GRPCTEST)
add_test(NAME grpctest COMMAND grpctest) add_test(NAME grpctest COMMAND grpctest)
endif() endif()
......
...@@ -1837,6 +1837,9 @@ class CppGenerator : public BaseGenerator { ...@@ -1837,6 +1837,9 @@ class CppGenerator : public BaseGenerator {
code_ += " typedef {{NATIVE_NAME}} NativeTableType;"; code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
} }
code_ += " typedef {{STRUCT_NAME}}Builder Builder;"; code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
code_ += " struct Traits;";
}
if (opts_.mini_reflect != IDLOptions::kNone) { if (opts_.mini_reflect != IDLOptions::kNone) {
code_ += code_ +=
" static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
...@@ -2198,6 +2201,16 @@ class CppGenerator : public BaseGenerator { ...@@ -2198,6 +2201,16 @@ class CppGenerator : public BaseGenerator {
code_ += "}"; code_ += "}";
code_ += ""; code_ += "";
// Definition for type traits for this table type. This allows querying var-
// ious compile-time traits of the table.
if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
code_ += "struct {{STRUCT_NAME}}::Traits {";
code_ += " using type = {{STRUCT_NAME}};";
code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
code_ += "};";
code_ += "";
}
// Generate a CreateXDirect function with vector types as parameters // Generate a CreateXDirect function with vector types as parameters
if (has_string_or_vector_fields) { if (has_string_or_vector_fields) {
code_ += code_ +=
......
...@@ -621,6 +621,7 @@ struct InParentNamespaceT : public flatbuffers::NativeTable { ...@@ -621,6 +621,7 @@ struct InParentNamespaceT : public flatbuffers::NativeTable {
struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef InParentNamespaceT NativeTableType; typedef InParentNamespaceT NativeTableType;
typedef InParentNamespaceBuilder Builder; typedef InParentNamespaceBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return InParentNamespaceTypeTable(); return InParentNamespaceTypeTable();
} }
...@@ -655,6 +656,11 @@ inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace( ...@@ -655,6 +656,11 @@ inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(
return builder_.Finish(); return builder_.Finish();
} }
struct InParentNamespace::Traits {
using type = InParentNamespace;
static auto constexpr Create = CreateInParentNamespace;
};
flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
namespace Example2 { namespace Example2 {
...@@ -668,6 +674,7 @@ struct MonsterT : public flatbuffers::NativeTable { ...@@ -668,6 +674,7 @@ struct MonsterT : public flatbuffers::NativeTable {
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef MonsterT NativeTableType; typedef MonsterT NativeTableType;
typedef MonsterBuilder Builder; typedef MonsterBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return MonsterTypeTable(); return MonsterTypeTable();
} }
...@@ -702,6 +709,11 @@ inline flatbuffers::Offset<Monster> CreateMonster( ...@@ -702,6 +709,11 @@ inline flatbuffers::Offset<Monster> CreateMonster(
return builder_.Finish(); return builder_.Finish();
} }
struct Monster::Traits {
using type = Monster;
static auto constexpr Create = CreateMonster;
};
flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
} // namespace Example2 } // namespace Example2
...@@ -719,6 +731,7 @@ struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable { ...@@ -719,6 +731,7 @@ struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TestSimpleTableWithEnumT NativeTableType; typedef TestSimpleTableWithEnumT NativeTableType;
typedef TestSimpleTableWithEnumBuilder Builder; typedef TestSimpleTableWithEnumBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return TestSimpleTableWithEnumTypeTable(); return TestSimpleTableWithEnumTypeTable();
} }
...@@ -768,6 +781,11 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnu ...@@ -768,6 +781,11 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnu
return builder_.Finish(); return builder_.Finish();
} }
struct TestSimpleTableWithEnum::Traits {
using type = TestSimpleTableWithEnum;
static auto constexpr Create = CreateTestSimpleTableWithEnum;
};
flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct StatT : public flatbuffers::NativeTable { struct StatT : public flatbuffers::NativeTable {
...@@ -784,6 +802,7 @@ struct StatT : public flatbuffers::NativeTable { ...@@ -784,6 +802,7 @@ struct StatT : public flatbuffers::NativeTable {
struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef StatT NativeTableType; typedef StatT NativeTableType;
typedef StatBuilder Builder; typedef StatBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return StatTypeTable(); return StatTypeTable();
} }
...@@ -860,6 +879,11 @@ inline flatbuffers::Offset<Stat> CreateStat( ...@@ -860,6 +879,11 @@ inline flatbuffers::Offset<Stat> CreateStat(
return builder_.Finish(); return builder_.Finish();
} }
struct Stat::Traits {
using type = Stat;
static auto constexpr Create = CreateStat;
};
inline flatbuffers::Offset<Stat> CreateStatDirect( inline flatbuffers::Offset<Stat> CreateStatDirect(
flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::FlatBufferBuilder &_fbb,
const char *id = nullptr, const char *id = nullptr,
...@@ -886,6 +910,7 @@ struct ReferrableT : public flatbuffers::NativeTable { ...@@ -886,6 +910,7 @@ struct ReferrableT : public flatbuffers::NativeTable {
struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef ReferrableT NativeTableType; typedef ReferrableT NativeTableType;
typedef ReferrableBuilder Builder; typedef ReferrableBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return ReferrableTypeTable(); return ReferrableTypeTable();
} }
...@@ -941,6 +966,11 @@ inline flatbuffers::Offset<Referrable> CreateReferrable( ...@@ -941,6 +966,11 @@ inline flatbuffers::Offset<Referrable> CreateReferrable(
return builder_.Finish(); return builder_.Finish();
} }
struct Referrable::Traits {
using type = Referrable;
static auto constexpr Create = CreateReferrable;
};
flatbuffers::Offset<Referrable> CreateReferrable(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<Referrable> CreateReferrable(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct MonsterT : public flatbuffers::NativeTable { struct MonsterT : public flatbuffers::NativeTable {
...@@ -1017,6 +1047,7 @@ struct MonsterT : public flatbuffers::NativeTable { ...@@ -1017,6 +1047,7 @@ struct MonsterT : public flatbuffers::NativeTable {
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef MonsterT NativeTableType; typedef MonsterT NativeTableType;
typedef MonsterBuilder Builder; typedef MonsterBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return MonsterTypeTable(); return MonsterTypeTable();
} }
...@@ -1766,6 +1797,11 @@ inline flatbuffers::Offset<Monster> CreateMonster( ...@@ -1766,6 +1797,11 @@ inline flatbuffers::Offset<Monster> CreateMonster(
return builder_.Finish(); return builder_.Finish();
} }
struct Monster::Traits {
using type = Monster;
static auto constexpr Create = CreateMonster;
};
inline flatbuffers::Offset<Monster> CreateMonsterDirect( inline flatbuffers::Offset<Monster> CreateMonsterDirect(
flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::FlatBufferBuilder &_fbb,
const MyGame::Example::Vec3 *pos = 0, const MyGame::Example::Vec3 *pos = 0,
...@@ -1920,6 +1956,7 @@ struct TypeAliasesT : public flatbuffers::NativeTable { ...@@ -1920,6 +1956,7 @@ struct TypeAliasesT : public flatbuffers::NativeTable {
struct TypeAliases FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct TypeAliases FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TypeAliasesT NativeTableType; typedef TypeAliasesT NativeTableType;
typedef TypeAliasesBuilder Builder; typedef TypeAliasesBuilder Builder;
struct Traits;
static const flatbuffers::TypeTable *MiniReflectTypeTable() { static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return TypeAliasesTypeTable(); return TypeAliasesTypeTable();
} }
...@@ -2114,6 +2151,11 @@ inline flatbuffers::Offset<TypeAliases> CreateTypeAliases( ...@@ -2114,6 +2151,11 @@ inline flatbuffers::Offset<TypeAliases> CreateTypeAliases(
return builder_.Finish(); return builder_.Finish();
} }
struct TypeAliases::Traits {
using type = TypeAliases;
static auto constexpr Create = CreateTypeAliases;
};
inline flatbuffers::Offset<TypeAliases> CreateTypeAliasesDirect( inline flatbuffers::Offset<TypeAliases> CreateTypeAliasesDirect(
flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::FlatBufferBuilder &_fbb,
int8_t i8 = 0, int8_t i8 = 0,
......
...@@ -36,8 +36,31 @@ namespace cpp11 { ...@@ -36,8 +36,31 @@ namespace cpp11 {
#include "../monster_test_generated.h" #include "../monster_test_generated.h"
} // namespace cpp11 } // namespace cpp11
void CreateTableByTypeTest() {
flatbuffers::FlatBufferBuilder builder;
// We will create an object of this type using only the type.
using type_to_create_t = cpp17::MyGame::Example::Stat;
[&builder] {
auto id_str = builder.CreateString("my_id");
auto table = type_to_create_t::Traits::Create(builder, id_str, 42, 7);
// Be sure that the correct return type was inferred.
static_assert(
std::is_same_v<decltype(table), flatbuffers::Offset<type_to_create_t>>);
builder.Finish(table);
}();
// Access it.
auto stat =
flatbuffers::GetRoot<type_to_create_t>(builder.GetBufferPointer());
TEST_EQ_STR(stat->id()->c_str(), "my_id");
TEST_EQ(stat->val(), 42);
TEST_EQ(stat->count(), 7);
}
int FlatBufferCpp17Tests() { int FlatBufferCpp17Tests() {
TEST_ASSERT(true); CreateTableByTypeTest();
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment