Получить самый внутренний тип шаблона внутри самого шаблона
возможно ли извлечь изнутри шаблон сокрытых шаблонов одного типа из одного типа? Я хотел бы получить double
тип в следующем примере:
template<typename T>
struct is_a : std::false_type {};
template<typename T>
struct A
{
using type = std::conditional_t<
is_a<T>::value,
T::type, // if it an A, go deeper
T>; // if not, we're done
};
template<typename T>
struct is_a<A<T>> : std::true_type {};
int main()
{
A<A<A<A<A<double>>>>>::type d = 3.0;
return 0;
}
Это было мотивировано этим вопросом. Кроме того, я нашел этот пост, указав, что он может что-то делать с использованием ключевого слова typename
или template
, но я не мог заставить его работать сам.
Ответы
Ответ 1
Обычный трюк, чтобы сделать это с вашим первоначальным подходом, - это отложить оценку:
template<class T> struct type_identity { using type = T; };
template<typename T>
struct A
{
using type = typename std::conditional_t<
is_a<T>::value,
T,
type_identity<T>>::type;
};
Ответ 2
Если я не пропущу что-то, я бы только частично специализировал шаблон, чтобы упростить
template<typename T>
struct A
{
using type = T;
};
template<typename T>
struct A<A<T>>
{
using type = typename A<T>::type;
};
int main()
{
A<double>::type a = 5.0;
A<A<double>>::type d = 3.0;
A<A<A<double>>>::type c = 9.5;
return 0;
}
Live sample
Ответ 3
Кроме того, ваш опечатка отсутствует typename
, проблема здесь:
using type = std::conditional_t<
is_a<T>::value,
T::type, // if it an A, go deeper
T>; // if not, we're done
что std::conditional
не является короткозамкнутым. Если T
не имеет члена type
, это приведет к ошибке.
Вы можете написать мета-функцию для рекурсивного извлечения внутреннего типа:
template<class T>
struct extract_type {
using type = T;
};
template<class T> class A;
template<class T>
struct extract_type<A<T>> {
using type = typename extract_type<T>::type;
};
template<typename T>
struct A
{
using type = typename extract_type<T>::type;
};
int main()
{
A<A<A<A<A<double>>>>>::type d = 3.0;
return 0;
}
Ответ 4
Вы можете использовать enable_if
и SFINAE для выбора самого сокровенного типа:
template<typename T, class Enable = void>
struct A {
using type = T;
};
template<typename T>
struct A<T, std::enable_if_t<!std::is_same_v<T, typename T::type>>> {
using type = typename T::type;
};
Ответ 5
Альтернатива Марко (правильный) ответ. Вы можете поместить некоторые из этих логик выбора типа в класс признаков:
// step 1 - predeclare the template A
template<typename T> struct A;
// define a default specialisation of a traits type
template<class T> struct ATraits
{
using type = T;
};
// specialise the traits for the A<T> case
template<class T> struct ATraits<A<T>>
{
using type = typename A<T>::type;
};
// now define the A template default specialisation
template<typename T>
struct A
{
using type = typename ATraits<T>::type;
};
int main()
{
A<A<A<A<A<double>>>>>::type d = 3.0;
return 0;
}