Suppose I have common code that I would like to reuse for several classes that implement the same basic functions but have interfaces with different member function names. For example, the following code will work if the base class has an erase member erase , for example. std::set or std::unordered_set .
template <typename T> static std::chrono::duration<double> set_insert_time(const typename T::value_type &v) { T set; std::chrono::time_point<std::chrono::high_resolution_clock> start, end; start = std::chrono::high_resolution_clock::now(); set.erase(v); end = std::chrono::high_resolution_clock::now(); return end - start; }
But now I want this function to work, for example. tbb::concurrent_unordered_set , which instead performs a function called unsafe_erase .
My initial approach was to use type properties with a partial template specialization, defining the following and calling set_ops<T>::erase(set, v) . Unfortunately, this does not compile because tbb::concurrent_unordered_set is a template, not a type. I also tried extending the type property with the second template argument for the key type, but this does not compile because T not a template in std::mem_fn(&T<U>::erase) .
template <typename T> struct set_ops { constexpr static auto erase = std::mem_fn(&T::erase); }; template <> struct set_ops<tbb::concurrent_unordered_set> { constexpr static auto erase = std::mem_fn(&T::unsafe_erase); };
I also tried wrapping a member function with a function template as follows. This seems to be compiling but not linking due to undefined links, for example. decltype ((({parm#1}.erase)({parm#2})),((bool)())) erase<std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> > >(std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> >&, std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> >::key_type const&)
template <typename T> constexpr auto set_erase(T& s, const typename T::key_type &v) -> decltype(s.erase(v), bool()); template <typename T> constexpr auto set_erase(T& s, const typename T::key_type &v) -> decltype(s.unsafe_erase(v), bool());
How do I do this overlay at compile time? I know that I could provide an implementation that inherits from an abstract interface for each base class, or use a pointer to a member function, but I would like to avoid any extra time.