Suppose I have
class A {};
template<typename T, typename U> class Wrapper {};
I'm trying to check if the wrapper's first inner type is A
.
typeCheck(new A(), new Wrapper<A,B>); // expect true
typeCheck(new A(), new Wrapper<C,B>); // expect false
What's the best approach to do it?
I've tried template partial specialization but did not have luck.
Here is the code I tried:
template<typename T> struct get_inner {
using type = T;
}
template<typename T, typename U>
struct get_inner<Wrapper<T,U>> {
using type = T;
}
std::cout<< typeid(get_inner<decltype(new Wrapper<A,B>)>::type);
The console shows the same wrapper type instead of the inner type A
. Is there anything mistake here?
The console shows the same wrapper type instead of the inner type
A
. Is there anything mistake here?
The type of new Wrapper<A,B>
is a pointer to the Wrapper<A,B>
, not Wrapper
itself. Therefore, it doesn't suit to your specialization, and chose the first base template, where type
is equal to the passed type, which is Wrapper<A,B>*
.
Instead, you should have written
typename get_inner<Wrapper<A,B>>::type;
Note that, the decltype
is also unnecessary because you are passing the template type itself already.
Since you are trying to see check the type at compile time, I would suggest using std::is_same
as well. For example
std::cout << std::boolalpha
<< std::is_same_v<typename get_inner<Wrapper<A,B>>::type, A>;
What's the best approach to do it?
Well, there are many ways!
One way is to do, like std::is_same_v
, in standard type traits, you can write traits for this directly:
#include <type_traits> // std::false_type, std::true_type
template<typename T> // base template
struct is_inner_type : std::false_type{};
template<typename T, typename U> // specialization
struct is_inner_type<Wrapper<T,U>> {
static constexpr bool value = std::is_same_v<A, T>;
};
// variable template for convenience
template<typename ClassType>
inline constexpr bool is_inner_type_v = is_inner_type<ClassType>::value;
And you would use it like
static_assert(!is_inner_type_v<Wrapper<int, float>>);
static_assert(is_inner_type_v<Wrapper<A, float>>);
However, that is not generic enough to change the type to be checked. There, I would suggest something similar to your original implementation.
// traits for finding the T & U type!
template <typename T> struct Class;
template <template<typename A, typename B> class Type, typename A, typename B>
struct Class<Type<A,B>> {
using T = A;
// using U = B; // if needed
};
template <typename Type> using class_t = typename Class<Type>::T;
// template <typename Type> using class_u = typename Class<Type>::U; // if needed
// variable template for convenience
template<typename ClassType, typename TypeToCheck>
inline constexpr bool is_inner_type_v = std::is_same_v<class_t<ClassType>, TypeToCheck>;
I used, template template class specialization, in case you want to make it more generic and use it for other similar class templates.