From 4055ff6ff7a8a42d828f8dc01f032387cd6e1811 Mon Sep 17 00:00:00 2001 From: Nathan Hughes Date: Mon, 25 Nov 2024 16:52:52 +0000 Subject: [PATCH] allow virtual configs to be templated to set optional value before constructing --- .../include/config_utilities/virtual_config.h | 17 ++++----- .../test/tests/virtual_config.cpp | 36 +++++++++++++++++++ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/config_utilities/include/config_utilities/virtual_config.h b/config_utilities/include/config_utilities/virtual_config.h index d27e4ef..f3db149 100644 --- a/config_utilities/include/config_utilities/virtual_config.h +++ b/config_utilities/include/config_utilities/virtual_config.h @@ -50,8 +50,9 @@ namespace config { * class. * * @tparam BaseT The base class of the object that should be created from the config. + * @tparam BaseT Whether or not the virtual config is optional when constructed (useful for maps and vectors of configs) */ -template +template class VirtualConfig { public: VirtualConfig() = default; @@ -184,25 +185,25 @@ class VirtualConfig { } private: - template - friend void declare_config(VirtualConfig&); + template + friend void declare_config(VirtualConfig&); friend struct internal::Visitor; - bool optional_ = false; + bool optional_ = OptionalByDefault; std::unique_ptr config_; }; namespace internal { // Declare virtual config types. -template -struct is_virtual_config> : std::true_type {}; +template +struct is_virtual_config> : std::true_type {}; } // namespace internal // Declare the Virtual Config a config, so it can be handled like any other object. -template -void declare_config(VirtualConfig& config) { +template +void declare_config(VirtualConfig& config) { auto data = internal::Visitor::visitVirtualConfig(config.isSet(), config.optional_, config.getType()); // underlying derived type is not required if the config is optional, or if the config has been diff --git a/config_utilities/test/tests/virtual_config.cpp b/config_utilities/test/tests/virtual_config.cpp index 85ef47f..0e21887 100644 --- a/config_utilities/test/tests/virtual_config.cpp +++ b/config_utilities/test/tests/virtual_config.cpp @@ -117,6 +117,27 @@ void declare_config(ObjectWithBase::Config& config) { config::field(config.base_config, "base_config", false); } +struct ObjectWithOptionalConfigs { + struct Config { + std::vector> modules; + } const config; + + explicit ObjectWithOptionalConfigs(const Config& config) : config(config::checkValid(config)) { + for (const auto& base_config : config.modules) { + if (base_config) { + valid.emplace_back(base_config.create()); + } + } + } + + std::vector> valid; +}; + +void declare_config(ObjectWithOptionalConfigs::Config& config) { + config::name("ObjectWithOptionalConfigs"); + config::field(config.modules, "modules"); +} + TEST(VirtualConfig, isSet) { Settings().restoreDefaults(); @@ -348,4 +369,19 @@ TEST(VirtualConfig, getUnderlying) { EXPECT_TRUE(config.getUnderlying()); } +TEST(VirtualConfig, optionalByDefault) { + Settings().restoreDefaults(); + + const std::string yaml_str = R"""(modules: + - {type: testing} + - {a: 5, b: 6} + - {type: Derived2} +)"""; + + const auto node = YAML::Load(yaml_str); + const auto config = config::fromYaml(node); + const ObjectWithOptionalConfigs object(config); + EXPECT_EQ(object.valid.size(), 1u); +} + } // namespace config::test