Я хотел бы знать, как решить следующую проблему (C ++ 17): предположим, есть несколько шаблонных классов, унаследованных друг от друга в стиле CRTP (только одиночное наследование).Для заданного базового класса экземпляра шаблона найдите класс, который находится дальше всего от него по цепочке наследования.
Сначала я подумал, что это должно быть довольно легко, но не смог этого сделать.
Для упрощения предположим, что каждый корень и каждый промежуточный класс имеют using DerivedT = Derived
в своей области public
.
Пример:
template <class T>
struct GetDeepest {
using Type = ...;
};
template <class T>
struct A {
using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
GetDeepest<A<D>>::Type == D;
GetDeepest<B<C>>::Type == C;
GetDeepest<A<B<C>>>::Type == C;
...
Первая реализация, которую я пробовал:
template <class T>
struct GetDeepest {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
using Type = std::conditional_t<std::is_same_v<std::true_type, HelperType>,
GetDeepest<typename T::DerivedT>::Type,
T>;
};
Вторая реализация, которую я пробовал:
template <class T>
struct HasNext {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
static const bool value = std::is_same_v<std::true_type, HelperType>;
};
template <class T>
auto GetDeepestHelper(const T& val) {
if constexpr(HasNext<T>::value) {
return GetDeepestHelper(std::declval<typename T::DerivedT>());
} else {
return val;
}
}
template <class T>
struct GetDeepest {
using Type = decltype(GetDeepestLevelHelper(std::declval<T>()));
};
Ни одна из них не компилируется.
Первая - из-за неполного типа GetDeepest<T>
в выражении using Type = ...
во-вторых, из-за рекурсивного вызова функции с auto
в качестве возвращаемого типа.
Можно ли вообще реализовать класс GetDeepest<T>
с такими свойствами?Теперь мне очень любопытно, даже если это не самый лучший способ достичь того, чего я хочу.
Спасибо!