diff --git a/src/util/IntrusiveHashSet.hxx b/src/util/IntrusiveHashSet.hxx index fb949d642..4f4d2f5fb 100644 --- a/src/util/IntrusiveHashSet.hxx +++ b/src/util/IntrusiveHashSet.hxx @@ -25,29 +25,26 @@ struct IntrusiveHashSetHook { } }; -/** - * Detect the hook type. - */ -template<typename U> -struct IntrusiveHashSetHookDetection { - /* TODO can this be simplified somehow, without checking for - all possible enum values? */ - using type = std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::NORMAL>, U>, - IntrusiveHashSetHook<IntrusiveHookMode::NORMAL>, - std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::TRACK>, U>, - IntrusiveHashSetHook<IntrusiveHookMode::TRACK>, - std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::AUTO_UNLINK>, U>, - IntrusiveHashSetHook<IntrusiveHookMode::AUTO_UNLINK>, - void>>>; -}; - /** * For classes which embed #IntrusiveHashSetHook as base class. */ template<typename T> struct IntrusiveHashSetBaseHookTraits { + /* a never-called helper function which is used by _Cast() */ + template<IntrusiveHookMode mode> + static constexpr IntrusiveHashSetHook<mode> _Identity(const IntrusiveHashSetHook<mode> &) noexcept; + + /* another never-called helper function which "calls" + _Identity(), implicitly casting the item to the + IntrusiveHashSetHook specialization; we use this to detect + which IntrusiveHashSetHook specialization is used */ template<typename U> - using Hook = typename IntrusiveHashSetHookDetection<U>::type; + static constexpr auto _Cast(const U &u) noexcept { + return decltype(_Identity(u))(); + } + + template<typename U> + using Hook = decltype(_Cast(std::declval<U>())); static constexpr T *Cast(Hook<T> *node) noexcept { return static_cast<T *>(node); diff --git a/src/util/IntrusiveList.hxx b/src/util/IntrusiveList.hxx index 27e5975d9..64ba6aaaf 100644 --- a/src/util/IntrusiveList.hxx +++ b/src/util/IntrusiveList.hxx @@ -77,31 +77,26 @@ using SafeLinkIntrusiveListHook = using AutoUnlinkIntrusiveListHook = IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>; -/** - * Detect the hook type which is embedded in the given type as a base - * class. This is a template to postpone the type checks, to allow - * forward-declared types. - */ -template<typename U> -struct IntrusiveListHookDetection { - /* TODO can this be simplified somehow, without checking for - all possible enum values? */ - using type = std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::NORMAL>, U>, - IntrusiveListHook<IntrusiveHookMode::NORMAL>, - std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::TRACK>, U>, - IntrusiveListHook<IntrusiveHookMode::TRACK>, - std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>, U>, - IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>, - void>>>; -}; - /** * For classes which embed #IntrusiveListHook as base class. */ template<typename T> struct IntrusiveListBaseHookTraits { + /* a never-called helper function which is used by _Cast() */ + template<IntrusiveHookMode mode> + static constexpr IntrusiveListHook<mode> _Identity(const IntrusiveListHook<mode> &) noexcept; + + /* another never-called helper function which "calls" + _Identity(), implicitly casting the item to the + IntrusiveListHook specialization; we use this to detect + which IntrusiveListHook specialization is used */ template<typename U> - using Hook = typename IntrusiveListHookDetection<U>::type; + static constexpr auto _Cast(const U &u) noexcept { + return decltype(_Identity(u))(); + } + + template<typename U> + using Hook = decltype(_Cast(std::declval<U>())); static constexpr T *Cast(IntrusiveListNode *node) noexcept { auto *hook = &Hook<T>::Cast(*node);