From 018ba2413868867de90bbc402c21ab8142b2af9d Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Fri, 12 Jun 2026 10:58:19 +0200 Subject: [PATCH 1/3] Include CPP20 and related changes Signed-off-by: Alejandro Hernandez Cordero --- CMakeLists.txt | 16 ++++++++++----- include/class_loader/meta_object.hpp | 3 ++- .../multi_library_class_loader.hpp | 2 +- package.xml | 1 + src/class_loader_core.cpp | 20 ++++++------------- src/meta_object.cpp | 15 +++++++------- src/multi_library_class_loader.cpp | 20 +++++++++---------- 7 files changed, 38 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eafb864..67df721f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,9 @@ cmake_minimum_required(VERSION 3.20) project(class_loader) -# Default to C++17 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) - set(CMAKE_CXX_STANDARD_REQUIRED ON) -endif() +# The C++/C standard comes from ament_ros_defaults (cxx_std_20 / c_std_17), +# linked PRIVATE below so it applies to this library's own translation units +# only and is not propagated to downstream consumers. if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() @@ -15,6 +13,7 @@ set(CLASS_LOADER_IGNORE_AMENT FALSE CACHE BOOL "Do not use ament when building this package.") if(NOT CLASS_LOADER_IGNORE_AMENT) find_package(ament_cmake REQUIRED) + find_package(ament_cmake_ros_core REQUIRED) set(explicit_library_type "SHARED") else() set(explicit_library_type "SHARED") @@ -44,11 +43,18 @@ if(ament_cmake_FOUND) target_link_libraries(${PROJECT_NAME} PUBLIC console_bridge::console_bridge rcpputils::rcpputils) + # ament_ros_defaults is an INTERFACE target providing cxx_std_20 / c_std_17. + # Linked PRIVATE so the standard applies to our own sources without leaking + # into the exported interface (a SHARED library does not propagate PRIVATE + # link requirements to consumers). + target_link_libraries(${PROJECT_NAME} PRIVATE ament_cmake_ros_core::ament_ros_defaults) ament_export_targets(${PROJECT_NAME}) else() target_include_directories(${PROJECT_NAME} PUBLIC ${console_bridge_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} ${console_bridge_LIBRARIES}) + # Standalone (non-ament) build: request C++20 for our own translation units. + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) endif() if(WIN32) # Causes the visibility macros to use dllexport rather than dllimport diff --git a/include/class_loader/meta_object.hpp b/include/class_loader/meta_object.hpp index 0b416200..dc7ec4b3 100644 --- a/include/class_loader/meta_object.hpp +++ b/include/class_loader/meta_object.hpp @@ -34,6 +34,7 @@ #ifndef CLASS_LOADER__META_OBJECT_HPP_ #define CLASS_LOADER__META_OBJECT_HPP_ +#include #include #include #include @@ -151,7 +152,7 @@ class CLASS_LOADER_PUBLIC AbstractMetaObjectBase */ virtual void dummyMethod() {} - AbstractMetaObjectBaseImpl * impl_; + std::unique_ptr impl_; }; template diff --git a/include/class_loader/multi_library_class_loader.hpp b/include/class_loader/multi_library_class_loader.hpp index d1ac0352..78618307 100644 --- a/include/class_loader/multi_library_class_loader.hpp +++ b/include/class_loader/multi_library_class_loader.hpp @@ -379,7 +379,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ void shutdownAllClassLoaders(); - MultiLibraryClassLoaderImpl * impl_; + std::unique_ptr impl_; }; diff --git a/package.xml b/package.xml index d39ad953..258ca9c0 100644 --- a/package.xml +++ b/package.xml @@ -23,6 +23,7 @@ libconsole-bridge-dev ament_cmake + ament_cmake_ros_core console_bridge_vendor libconsole-bridge-dev diff --git a/src/class_loader_core.cpp b/src/class_loader_core.cpp index 7bfb53af..e8089532 100644 --- a/src/class_loader_core.cpp +++ b/src/class_loader_core.cpp @@ -30,6 +30,7 @@ #include "class_loader/class_loader_core.hpp" #include "class_loader/class_loader.hpp" +#include #include #include #include @@ -63,13 +64,9 @@ BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap() FactoryMap & getFactoryMapForBaseClass(const std::string & typeid_base_class_name) { - BaseToFactoryMapMap & factoryMapMap = getGlobalPluginBaseToFactoryMapMap(); - std::string base_class_name = typeid_base_class_name; - if (factoryMapMap.find(base_class_name) == factoryMapMap.end()) { - factoryMapMap[base_class_name] = FactoryMap(); - } - - return factoryMapMap[base_class_name]; + // std::map::operator[] value-initializes (an empty FactoryMap) when the key is + // absent, so a single lookup both finds and inserts as needed. + return getGlobalPluginBaseToFactoryMapMap()[typeid_base_class_name]; } MetaObjectGraveyardVector & getMetaObjectGraveyard() @@ -275,12 +272,7 @@ bool areThereAnyExistingMetaObjectsForLibrary(const std::string & library_path) LibraryVector::iterator findLoadedLibrary(const std::string & library_path) { LibraryVector & open_libraries = getLoadedLibraryVector(); - for (auto it = open_libraries.begin(); it != open_libraries.end(); ++it) { - if (it->first == library_path) { - return it; - } - } - return open_libraries.end(); + return std::ranges::find(open_libraries, library_path, &LibraryPair::first); } bool isLibraryLoadedByAnybody(const std::string & library_path) @@ -317,7 +309,7 @@ std::vector getAllLibrariesUsedByClassLoader(const ClassLoader * lo std::vector all_libs; for (auto & meta_obj : all_loader_meta_objs) { std::string lib_path = meta_obj->getAssociatedLibraryPath(); - if (std::find(all_libs.begin(), all_libs.end(), lib_path) == all_libs.end()) { + if (std::ranges::find(all_libs, lib_path) == all_libs.end()) { all_libs.push_back(lib_path); } } diff --git a/src/meta_object.cpp b/src/meta_object.cpp index 002b55e2..17a49de4 100644 --- a/src/meta_object.cpp +++ b/src/meta_object.cpp @@ -27,6 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include #include @@ -38,7 +40,7 @@ namespace class_loader namespace impl { -typedef std::vector ClassLoaderVector; +using ClassLoaderVector = std::vector; class AbstractMetaObjectBaseImpl { @@ -53,7 +55,7 @@ class AbstractMetaObjectBaseImpl AbstractMetaObjectBase::AbstractMetaObjectBase( const std::string & class_name, const std::string & base_class_name, const std::string & typeid_base_class_name) -: impl_(new AbstractMetaObjectBaseImpl()) +: impl_(std::make_unique()) { impl_->associated_library_path_ = "Unknown"; impl_->base_class_name_ = base_class_name; @@ -71,7 +73,6 @@ AbstractMetaObjectBase::~AbstractMetaObjectBase() "class_loader.impl.AbstractMetaObjectBase: " "Destroying MetaObject %p (base = %s, derived = %s, library path = %s)", this, baseClassName().c_str(), className().c_str(), getAssociatedLibraryPath().c_str()); - delete impl_; } const std::string & AbstractMetaObjectBase::className() const @@ -102,7 +103,7 @@ void AbstractMetaObjectBase::setAssociatedLibraryPath(const std::string & librar void AbstractMetaObjectBase::addOwningClassLoader(ClassLoader * loader) { ClassLoaderVector & v = impl_->associated_class_loaders_; - if (std::find(v.begin(), v.end(), loader) == v.end()) { + if (std::ranges::find(v, loader) == v.end()) { v.push_back(loader); } } @@ -110,8 +111,7 @@ void AbstractMetaObjectBase::addOwningClassLoader(ClassLoader * loader) void AbstractMetaObjectBase::removeOwningClassLoader(const ClassLoader * loader) { ClassLoaderVector & v = impl_->associated_class_loaders_; - ClassLoaderVector::iterator itr = std::find(v.begin(), v.end(), loader); - if (itr != v.end()) { + if (auto itr = std::ranges::find(v, loader); itr != v.end()) { v.erase(itr); } } @@ -119,8 +119,7 @@ void AbstractMetaObjectBase::removeOwningClassLoader(const ClassLoader * loader) bool AbstractMetaObjectBase::isOwnedBy(const ClassLoader * loader) const { const ClassLoaderVector & v = impl_->associated_class_loaders_; - auto it = std::find(v.begin(), v.end(), loader); - return it != v.end(); + return std::ranges::find(v, loader) != v.end(); } bool AbstractMetaObjectBase::isOwnedByAnybody() const diff --git a/src/multi_library_class_loader.cpp b/src/multi_library_class_loader.cpp index 7ff7d09f..36f4aa01 100644 --- a/src/multi_library_class_loader.cpp +++ b/src/multi_library_class_loader.cpp @@ -29,7 +29,9 @@ #include "class_loader/multi_library_class_loader.hpp" +#include #include +#include #include #include #include @@ -37,7 +39,7 @@ namespace class_loader { -typedef std::vector> ClassLoaderPtrVector; +using ClassLoaderPtrVector = std::vector>; class ClassLoaderDependency { @@ -79,7 +81,7 @@ ClassLoaderPtrVectorImpl & getClassLoaderPtrVectorImpl() } MultiLibraryClassLoader::MultiLibraryClassLoader(bool enable_ondemand_loadunload) -: impl_(new MultiLibraryClassLoaderImpl()) +: impl_(std::make_unique()) { impl_->enable_ondemand_loadunload_ = enable_ondemand_loadunload; } @@ -87,7 +89,6 @@ MultiLibraryClassLoader::MultiLibraryClassLoader(bool enable_ondemand_loadunload MultiLibraryClassLoader::~MultiLibraryClassLoader() { shutdownAllClassLoaders(); - delete impl_; } std::vector MultiLibraryClassLoader::getRegisteredLibraries() const @@ -128,8 +129,7 @@ ClassLoaderVector MultiLibraryClassLoader::getAllAvailableClassLoaders() const bool MultiLibraryClassLoader::isLibraryAvailable(const std::string & library_name) const { std::vector available_libraries = getRegisteredLibraries(); - return available_libraries.end() != std::find( - available_libraries.begin(), available_libraries.end(), library_name); + return std::ranges::find(available_libraries, library_name) != available_libraries.end(); } void MultiLibraryClassLoader::loadLibrary(const std::string & library_path) @@ -161,11 +161,11 @@ int MultiLibraryClassLoader::unloadLibrary(const std::string & library_path) impl_->active_class_loaders_[library_path] = nullptr; std::lock_guard lock(getClassLoaderPtrVectorImpl().loader_mutex_); auto & class_loader_ptrs = getClassLoaderPtrVectorImpl().class_loader_ptrs_; - for (auto iter = class_loader_ptrs.begin(); iter != class_loader_ptrs.end(); ++iter) { - if (iter->get() == loader) { - class_loader_ptrs.erase(iter); - break; - } + if (auto iter = std::ranges::find( + class_loader_ptrs, loader, [](const auto & p) {return p.get();}); + iter != class_loader_ptrs.end()) + { + class_loader_ptrs.erase(iter); } } } From ce69d3674be702fb02006a0ac83cc0d087ef1c45 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Fri, 12 Jun 2026 11:16:21 +0200 Subject: [PATCH 2/3] Cpp20 part2 Signed-off-by: Alejandro Hernandez Cordero --- include/class_loader/class_loader.hpp | 25 ++++++++------- include/class_loader/class_loader_core.hpp | 16 +++++----- .../multi_library_class_loader.hpp | 31 ++++++++++--------- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/include/class_loader/class_loader.hpp b/include/class_loader/class_loader.hpp index 06dd4127..5a5e077d 100644 --- a/include/class_loader/class_loader.hpp +++ b/include/class_loader/class_loader.hpp @@ -108,7 +108,7 @@ class ClassLoader * @return vector of strings indicating names of instantiable classes derived from */ template - std::vector getAvailableClasses() const + [[nodiscard]] std::vector getAvailableClasses() const { return class_loader::impl::getAvailableClasses(this); } @@ -126,11 +126,12 @@ class ClassLoader */ template, bool> = true> - std::shared_ptr createInstance(const std::string & derived_class_name, Args &&... args) + [[nodiscard]] std::shared_ptr createInstance( + const std::string & derived_class_name, Args &&... args) { return std::shared_ptr( createRawInstance(derived_class_name, true, std::forward(args)...), - std::bind(&ClassLoader::onPluginDeletion, this, std::placeholders::_1) + [this](Base * p) {onPluginDeletion(p);} ); } @@ -151,12 +152,13 @@ class ClassLoader */ template, bool> = true> - UniquePtr createUniqueInstance(const std::string & derived_class_name, Args &&... args) + [[nodiscard]] UniquePtr createUniqueInstance( + const std::string & derived_class_name, Args &&... args) { Base * raw = createRawInstance(derived_class_name, true, std::forward(args)...); return std::unique_ptr>( raw, - std::bind(&ClassLoader::onPluginDeletion, this, std::placeholders::_1) + [this](Base * p) {onPluginDeletion(p);} ); } @@ -177,7 +179,8 @@ class ClassLoader */ template, bool> = true> - Base * createUnmanagedInstance(const std::string & derived_class_name, Args &&... args) + [[nodiscard]] Base * createUnmanagedInstance( + const std::string & derived_class_name, Args &&... args) { return createRawInstance(derived_class_name, false, std::forward(args)...); } @@ -190,7 +193,7 @@ class ClassLoader * @return true if yes it is available, false otherwise */ template - bool isClassAvailable(const std::string & class_name) const + [[nodiscard]] bool isClassAvailable(const std::string & class_name) const { std::vector available_classes = getAvailableClasses(); return std::find( @@ -202,7 +205,7 @@ class ClassLoader * * @return the full-qualified path and name of the library */ - CLASS_LOADER_PUBLIC + [[nodiscard]] CLASS_LOADER_PUBLIC const std::string & getLibraryPath() const; /** @@ -215,7 +218,7 @@ class ClassLoader * @param library_path The path to the library to load * @return true if library is loaded within this ClassLoader object's scope, otherwise false */ - CLASS_LOADER_PUBLIC + [[nodiscard]] CLASS_LOADER_PUBLIC bool isLibraryLoaded() const; /** @@ -224,7 +227,7 @@ class ClassLoader * * @return true if library is loaded within the scope of the plugin system, otherwise false */ - CLASS_LOADER_PUBLIC + [[nodiscard]] CLASS_LOADER_PUBLIC bool isLibraryLoadedByAnyClassloader() const; /** @@ -234,7 +237,7 @@ class ClassLoader * * @return true if ondemand load and unload is active, otherwise false */ - CLASS_LOADER_PUBLIC + [[nodiscard]] CLASS_LOADER_PUBLIC bool isOnDemandLoadUnloadEnabled() const; /** diff --git a/include/class_loader/class_loader_core.hpp b/include/class_loader/class_loader_core.hpp index 1e402f6f..917d9f4f 100644 --- a/include/class_loader/class_loader_core.hpp +++ b/include/class_loader/class_loader_core.hpp @@ -75,14 +75,14 @@ namespace impl { // Typedefs -typedef std::string LibraryPath; -typedef std::string ClassName; -typedef std::string BaseClassName; -typedef std::map FactoryMap; -typedef std::map BaseToFactoryMapMap; -typedef std::pair> LibraryPair; -typedef std::vector LibraryVector; -typedef std::vector MetaObjectVector; +using LibraryPath = std::string; +using ClassName = std::string; +using BaseClassName = std::string; +using FactoryMap = std::map; +using BaseToFactoryMapMap = std::map; +using LibraryPair = std::pair>; +using LibraryVector = std::vector; +using MetaObjectVector = std::vector; class MetaObjectGraveyardVector : public MetaObjectVector { public: diff --git a/include/class_loader/multi_library_class_loader.hpp b/include/class_loader/multi_library_class_loader.hpp index 78618307..4b70fd83 100644 --- a/include/class_loader/multi_library_class_loader.hpp +++ b/include/class_loader/multi_library_class_loader.hpp @@ -56,9 +56,9 @@ namespace class_loader { -typedef std::string LibraryPath; -typedef std::map LibraryToClassLoaderMap; -typedef std::vector ClassLoaderVector; +using LibraryPath = std::string; +using LibraryToClassLoaderMap = std::map; +using ClassLoaderVector = std::vector; class MultiLibraryClassLoaderImpl; @@ -94,7 +94,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - std::shared_ptr createInstance(const std::string & class_name, Args &&... args) + [[nodiscard]] std::shared_ptr createInstance( + const std::string & class_name, Args &&... args) { CONSOLE_BRIDGE_logDebug( "class_loader::MultiLibraryClassLoader: " @@ -125,7 +126,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - std::shared_ptr createInstance( + [[nodiscard]] std::shared_ptr createInstance( const std::string & class_name, const std::string & library_path, Args &&... args) { ClassLoader * loader = getClassLoaderForLibrary(library_path); @@ -151,7 +152,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - ClassLoader::UniquePtr createUniqueInstance(const std::string & class_name, Args &&... args) + [[nodiscard]] ClassLoader::UniquePtr createUniqueInstance( + const std::string & class_name, Args &&... args) { CONSOLE_BRIDGE_logDebug( "class_loader::MultiLibraryClassLoader: Attempting to create instance of class type %s.", @@ -180,7 +182,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - ClassLoader::UniquePtr + [[nodiscard]] ClassLoader::UniquePtr createUniqueInstance( const std::string & class_name, const std::string & library_path, Args &&... args) @@ -209,7 +211,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - Base * createUnmanagedInstance(const std::string & class_name, Args &&... args) + [[nodiscard]] Base * createUnmanagedInstance(const std::string & class_name, Args &&... args) { ClassLoader * loader = getClassLoaderForClass(class_name); if (nullptr == loader) { @@ -232,7 +234,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader */ template, bool> = true> - Base * createUnmanagedInstance( + [[nodiscard]] Base * createUnmanagedInstance( const std::string & class_name, const std::string & library_path, Args &&... args) { @@ -254,7 +256,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * @return true if loaded, false otherwise */ template - bool isClassAvailable(const std::string & class_name) const + [[nodiscard]] bool isClassAvailable(const std::string & class_name) const { std::vector available_classes = getAvailableClasses(); return available_classes.end() != std::find( @@ -267,7 +269,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * @param library_path - The full qualified path to the runtime library * @return true if library is loaded, false otherwise */ - bool isLibraryAvailable(const std::string & library_path) const; + [[nodiscard]] bool isLibraryAvailable(const std::string & library_path) const; /** * @brief Gets a list of all classes that are loaded by the class loader @@ -276,7 +278,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * @return A vector of the available classes */ template - std::vector getAvailableClasses() const + [[nodiscard]] std::vector getAvailableClasses() const { std::vector available_classes; for (auto & loader : getAllAvailableClassLoaders()) { @@ -294,7 +296,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * @return A vector of the available classes in the passed library */ template - std::vector getAvailableClassesForLibrary(const std::string & library_path) const + [[nodiscard]] std::vector getAvailableClassesForLibrary( + const std::string & library_path) const { const ClassLoader * loader = getClassLoaderForLibrary(library_path); if (nullptr == loader) { @@ -311,7 +314,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * * @return A list of libraries opened by this class loader */ - std::vector getRegisteredLibraries() const; + [[nodiscard]] std::vector getRegisteredLibraries() const; /** * @brief Loads a library into memory for this class loader From 34a43738f759a29a7a1c286fb22ce33b36561f94 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Fri, 12 Jun 2026 11:25:26 +0200 Subject: [PATCH 3/3] Cpp20 part3 Signed-off-by: Alejandro Hernandez Cordero --- include/class_loader/class_loader.hpp | 19 +++++------ include/class_loader/class_loader_core.hpp | 34 +++++++------------ include/class_loader/interface_traits.hpp | 19 +++++++++-- .../multi_library_class_loader.hpp | 28 +++++++-------- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/include/class_loader/class_loader.hpp b/include/class_loader/class_loader.hpp index 5a5e077d..5b521486 100644 --- a/include/class_loader/class_loader.hpp +++ b/include/class_loader/class_loader.hpp @@ -124,8 +124,8 @@ class ClassLoader * by InterfaceTraits of the Base class) * @return A std::shared_ptr to newly created plugin object */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] std::shared_ptr createInstance( const std::string & derived_class_name, Args &&... args) { @@ -150,8 +150,8 @@ class ClassLoader * by InterfaceTraits of the Base class) * @return A std::unique_ptr to newly created plugin object. */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] UniquePtr createUniqueInstance( const std::string & derived_class_name, Args &&... args) { @@ -177,8 +177,8 @@ class ClassLoader * by InterfaceTraits of the Base class) * @return An unmanaged (i.e. not a shared_ptr) Base* to newly created plugin object. */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] Base * createUnmanagedInstance( const std::string & derived_class_name, Args &&... args) { @@ -196,8 +196,7 @@ class ClassLoader [[nodiscard]] bool isClassAvailable(const std::string & class_name) const { std::vector available_classes = getAvailableClasses(); - return std::find( - available_classes.begin(), available_classes.end(), class_name) != available_classes.end(); + return std::ranges::find(available_classes, class_name) != available_classes.end(); } /** @@ -314,8 +313,8 @@ class ClassLoader * by InterfaceTraits of the Base class) * @return A Base* to newly created plugin object. */ - template, bool> = true> + template + requires InterfaceConstructible Base * createRawInstance(const std::string & derived_class_name, bool managed, Args &&... args) { if (!managed) { diff --git a/include/class_loader/class_loader_core.hpp b/include/class_loader/class_loader_core.hpp index 917d9f4f..418418b4 100644 --- a/include/class_loader/class_loader_core.hpp +++ b/include/class_loader/class_loader_core.hpp @@ -32,6 +32,7 @@ #ifndef CLASS_LOADER__CLASS_LOADER_CORE_HPP_ #define CLASS_LOADER__CLASS_LOADER_CORE_HPP_ +#include #include #include #include @@ -277,25 +278,16 @@ registerPlugin(const std::string & class_name, const std::string & base_class_na [](AbstractMetaObjectBase * p) { getPluginBaseToFactoryMapMapMutex().lock(); MetaObjectGraveyardVector & graveyard = getMetaObjectGraveyard(); - for (auto iter = graveyard.begin(); iter != graveyard.end(); ++iter) { - if (*iter == p) { - graveyard.erase(iter); - break; - } + if (auto iter = std::ranges::find(graveyard, p); iter != graveyard.end()) { + graveyard.erase(iter); } BaseToFactoryMapMap & factory_map_map = getGlobalPluginBaseToFactoryMapMap(); - bool erase_flag = false; - for (auto & factory_map_item : factory_map_map) { - FactoryMap & factory_map = factory_map_item.second; - for (auto iter = factory_map.begin(); iter != factory_map.end(); ++iter) { - if (iter->second == p) { - factory_map.erase(iter); - erase_flag = true; - break; - } - } - if (erase_flag) { + for (auto & [base_class_name, factory_map] : factory_map_map) { + if (auto iter = std::ranges::find(factory_map, p, &FactoryMap::value_type::second); + iter != factory_map.end()) + { + factory_map.erase(iter); break; } } @@ -318,7 +310,7 @@ registerPlugin(const std::string & class_name, const std::string & base_class_na // Add it to global factory map map getPluginBaseToFactoryMapMapMutex().lock(); FactoryMap & factoryMap = getFactoryMapForBaseClass(); - if (factoryMap.find(class_name) != factoryMap.end()) { + if (factoryMap.contains(class_name)) { CONSOLE_BRIDGE_logWarn( "class_loader.impl: SEVERE WARNING!!! " "A namespace collision has occurred with plugin factory for class %s. " @@ -349,16 +341,16 @@ registerPlugin(const std::string & class_name, const std::string & base_class_na * by InterfaceTraits of the Base class) * @return A pointer to newly created plugin, note caller is responsible for object destruction */ -template, bool> = true> +template +requires InterfaceConstructible Base * createInstance(const std::string & derived_class_name, ClassLoader * loader, Args &&... args) { AbstractMetaObject * factory = nullptr; getPluginBaseToFactoryMapMapMutex().lock(); FactoryMap & factoryMap = getFactoryMapForBaseClass(); - if (factoryMap.find(derived_class_name) != factoryMap.end()) { - factory = dynamic_cast *>(factoryMap[derived_class_name]); + if (auto it = factoryMap.find(derived_class_name); it != factoryMap.end()) { + factory = dynamic_cast *>(it->second); } else { CONSOLE_BRIDGE_logError( "class_loader.impl: No metaobject exists for class type %s.", derived_class_name.c_str()); diff --git a/include/class_loader/interface_traits.hpp b/include/class_loader/interface_traits.hpp index f7285be4..2c0b6686 100644 --- a/include/class_loader/interface_traits.hpp +++ b/include/class_loader/interface_traits.hpp @@ -103,15 +103,17 @@ struct InterfaceTraits namespace impl { -template +template struct interface_constructor_parameters_impl { using type = ConstructorParameters<>; }; +// Constrained partial specialization replaces the std::void_t detection idiom: +// it is selected when InterfaceTraits defines a `constructor_parameters` member. template -struct interface_constructor_parameters_impl::constructor_parameters>> +requires requires {typename InterfaceTraits::constructor_parameters;} +struct interface_constructor_parameters_impl { using type = typename InterfaceTraits::constructor_parameters; }; @@ -190,6 +192,17 @@ template constexpr bool is_interface_constructible_v = is_interface_constructible::value; +/** + * @brief Concept satisfied when a plugin deriving from @p Base can be constructed + * from @p Args, as declared by its InterfaceTraits. + * + * Used in place of std::enable_if to constrain the create*Instance() factories, + * yielding clearer diagnostics ("constraint not satisfied") on a mismatch. + * @see is_interface_constructible + */ +template +concept InterfaceConstructible = is_interface_constructible_v; + } // namespace class_loader #endif // CLASS_LOADER__INTERFACE_TRAITS_HPP_ diff --git a/include/class_loader/multi_library_class_loader.hpp b/include/class_loader/multi_library_class_loader.hpp index 4b70fd83..a8ea70e3 100644 --- a/include/class_loader/multi_library_class_loader.hpp +++ b/include/class_loader/multi_library_class_loader.hpp @@ -32,6 +32,7 @@ #ifndef CLASS_LOADER__MULTI_LIBRARY_CLASS_LOADER_HPP_ #define CLASS_LOADER__MULTI_LIBRARY_CLASS_LOADER_HPP_ +#include #include #include #include @@ -92,8 +93,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * by InterfaceTraits of the Base class) * @return A std::shared_ptr to newly created plugin */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] std::shared_ptr createInstance( const std::string & class_name, Args &&... args) { @@ -124,8 +125,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * by InterfaceTraits of the Base class) * @return A std::shared_ptr to newly created plugin */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] std::shared_ptr createInstance( const std::string & class_name, const std::string & library_path, Args &&... args) { @@ -150,8 +151,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * by InterfaceTraits of the Base class) * @return A unique pointer to newly created plugin */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] ClassLoader::UniquePtr createUniqueInstance( const std::string & class_name, Args &&... args) { @@ -180,8 +181,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * by InterfaceTraits of the Base class) * @return A unique pointer to newly created plugin */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] ClassLoader::UniquePtr createUniqueInstance( const std::string & class_name, const std::string & library_path, @@ -209,8 +210,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * by InterfaceTraits of the Base class) * @return An unmanaged Base* to newly created plugin */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] Base * createUnmanagedInstance(const std::string & class_name, Args &&... args) { ClassLoader * loader = getClassLoaderForClass(class_name); @@ -232,8 +233,8 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader * @param args - arguments for the constructor of the derived class (types defined * by InterfaceTraits of the Base class) */ - template, bool> = true> + template + requires InterfaceConstructible [[nodiscard]] Base * createUnmanagedInstance( const std::string & class_name, const std::string & library_path, Args &&... args) @@ -259,8 +260,7 @@ class CLASS_LOADER_PUBLIC MultiLibraryClassLoader [[nodiscard]] bool isClassAvailable(const std::string & class_name) const { std::vector available_classes = getAvailableClasses(); - return available_classes.end() != std::find( - available_classes.begin(), available_classes.end(), class_name); + return std::ranges::find(available_classes, class_name) != available_classes.end(); } /**