diff --git a/hardware_interface/include/hardware_interface/internal/interface_manager.h b/hardware_interface/include/hardware_interface/internal/interface_manager.h index 392fb58c0..acbdfa4f0 100644 --- a/hardware_interface/include/hardware_interface/internal/interface_manager.h +++ b/hardware_interface/include/hardware_interface/internal/interface_manager.h @@ -43,27 +43,16 @@ namespace hardware_interface { + +namespace internal +{ + // SFINAE workaround, so that we have reflection inside the template functions template struct CheckIsResourceManager { - // variable definitions for compiler-time logic - typedef char yes[1]; - typedef char no[2]; - - // method called if C is a ResourceManager - template - static yes& testRM(typename C::resource_manager_type*); - - // method called if C is not a ResourceManager - template - static no& testRM(...); - - // CheckIsResourceManager::value == true when T is a ResourceManager - static const bool value = (sizeof(testRM(0)) == sizeof(yes)); - // method called if C is a ResourceManager template - static yes& callCM(typename std::vector& managers, C* result, typename C::resource_manager_type*) + static void callCM(typename std::vector& managers, C* result, typename C::resource_manager_type*) { std::vector managers_in; // we have to typecase back to base class @@ -74,7 +63,7 @@ struct CheckIsResourceManager { // method called if C is not a ResourceManager template - static no& callCM(typename std::vector& managers, C* result, ...) {} + static void callCM(typename std::vector& managers, C* result, ...) {} // calls ResourceManager::concatManagers if C is a ResourceManager static const void callConcatManagers(typename std::vector& managers, T* result) @@ -83,20 +72,47 @@ struct CheckIsResourceManager { // method called if C is a ResourceManager template - static std::vector callGR(C* iface, typename C::resource_manager_type*) + static void callGR(std::vector &resources, C* iface, typename C::resource_manager_type*) { - return iface->getNames(); + resources = iface->getNames(); } // method called if C is not a ResourceManager template - static std::vector callGR(T* iface, ...) {} + static void callGR(std::vector &resources, T* iface, ...) { } // calls ResourceManager::concatManagers if C is a ResourceManager - static std::vector callGetResources(T* iface) - { return callGR(iface, 0); } + static void callGetResources(std::vector &resources, T* iface) + { return callGR(resources, iface, 0); } + + template + static T* newCI(boost::ptr_vector &guards, typename C::resource_manager_type*) + { + T* iface_combo = new T; + // save the new interface pointer to allow for its correct destruction + guards.push_back(static_cast(iface_combo)); + return iface_combo; + } + + // method called if C is not a ResourceManager + template + static T* newCI(boost::ptr_vector &guards, ...) { + // it is not a ResourceManager + ROS_ERROR("You cannot register multiple interfaces of the same type which are " + "not of type ResourceManager. There is no established protocol " + "for combining them."); + return NULL; + } + + static T* newCombinedInterface(boost::ptr_vector &guards) + { + return newCI(guards, 0); + } + }; +} // namespace internal + class InterfaceManager { public: @@ -118,14 +134,7 @@ class InterfaceManager ROS_WARN_STREAM("Replacing previously registered interface '" << iface_name << "'."); } interfaces_[iface_name] = iface; - - std::vector resources; - if(CheckIsResourceManager::value) - { - // it is a ResourceManager. Get the names of the resources - resources = CheckIsResourceManager::callGetResources(iface); - } - resources_[iface_name] = resources; + internal::CheckIsResourceManager::callGetResources(resources_[iface_name], iface); } void registerInterfaceManager(InterfaceManager* iface_man) @@ -187,15 +196,10 @@ class InterfaceManager iface_combo = static_cast(it_combo->second); } else { // no existing combined interface - if(CheckIsResourceManager::value) { - // it is a ResourceManager - - // create a new combined interface - iface_combo = new T; - // save the new interface pointer to allow for its correct destruction - interface_destruction_list_.push_back(reinterpret_cast(iface_combo)); + iface_combo = internal::CheckIsResourceManager::newCombinedInterface(interface_destruction_list_); + if(iface_combo) { // concat all of the resource managers together - CheckIsResourceManager::callConcatManagers(iface_list, iface_combo); + internal::CheckIsResourceManager::callConcatManagers(iface_list, iface_combo); // save the combined interface for if this is called again interfaces_combo_[type_name] = iface_combo; num_ifaces_registered_[type_name] = iface_list.size(); diff --git a/hardware_interface/test/interface_manager_test.cpp b/hardware_interface/test/interface_manager_test.cpp index bf7fd184b..51f72917a 100644 --- a/hardware_interface/test/interface_manager_test.cpp +++ b/hardware_interface/test/interface_manager_test.cpp @@ -34,6 +34,7 @@ using namespace hardware_interface; struct FooInterface { + FooInterface(int foo): foo(foo) {} int foo; }; @@ -50,7 +51,7 @@ struct BazInterface TEST(InterfaceManagerTest, InterfaceRegistration) { // Register interfaces - FooInterface foo_iface; + FooInterface foo_iface(0); BarInterface bar_iface; InterfaceManager iface_mgr; @@ -66,11 +67,8 @@ TEST(InterfaceManagerTest, InterfaceRegistration) TEST(InterfaceManagerTest, InterfaceRewriting) { // Two instances of the same interface - FooInterface foo_iface_1; - foo_iface_1.foo = 1; - - FooInterface foo_iface_2; - foo_iface_2.foo = 2; + FooInterface foo_iface_1(1); + FooInterface foo_iface_2(2); // Register first interface and validate it InterfaceManager iface_mgr; @@ -91,4 +89,3 @@ int main(int argc, char** argv) testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } -