是否可以从模板中检索最内层类型的相同类型的堆叠模板?我想在以下示例中检索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's 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;
}
这是question的动机。另外,我发现了这个post,表明它可能会对typename
或template
关键字的位置产生影响,但我无法让它自己工作。
答案 0 :(得分:34)
除非我遗漏某些内容,否则我只是部分专门化模板以简化操作
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;
}
答案 1 :(得分:11)
使用原始方法执行此操作的常用技巧是推迟评估:
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 :(得分:3)
除了错过typename
的错字外,问题还有:
using type = std::conditional_t<
is_a<T>::value,
T::type, // if it's 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;
}
答案 3 :(得分:1)
您可以使用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;
};
答案 4 :(得分:1)
替代马可(正确)答案。您可能希望将一些此类型选择逻辑放入traits类中:
// 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;
}