I am writing some program to call some APIs automatically through code generation.
In some cases I need to convert from a type Source
, to a type Target
, but these types come decorated with pointers, const, etc. So what I need to do is to remove all decorations such as pointer, const, array, etc, get the plain type to map it to another type, and later, apply the decorations back into the new type.
The implementation has lots of template specializations. Questions after the code. I cannot use constexpr
metaprogramming because I need to make it work with VS2013.
template <class T>
struct TypeIs {
using type = T;
};
template <class T>
struct GetPlainType : TypeIs<typename std::decay<T>::type> {};
template <class T>
struct GetPlainType<T&> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T const &> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T &&> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T const &&> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T*> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T const *> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T const> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T[]> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
struct GetPlainType<T const[]> : TypeIs<typename GetPlainType<T>::type> {};
template <class T, std::size_t I>
struct GetPlainType<T[I]> : TypeIs<typename GetPlainType<T>::type> {};
template <class T, std::size_t I>
struct GetPlainType<T const [I]> : TypeIs<typename GetPlainType<T>::type> {};
template <class T>
using GetPlainType_t = typename GetPlainType<T>::type;
template <class Decorated, class Plain>
struct CopyDecorations : TypeIs<Plain> {};
template <class T, class Plain>
struct CopyDecorations<T const, Plain> :
TypeIs<typename CopyDecorations<T, Plain const>::type> {};
template <class T, class Plain>
struct CopyDecorations<T *, Plain> :
TypeIs<typename CopyDecorations<T, Plain *>::type> {};
template <class T, class Plain>
struct CopyDecorations<T const *, Plain> :
TypeIs<typename CopyDecorations<T, Plain const *>::type> {};
template <class T, class Plain>
struct CopyDecorations<T &, Plain> :
TypeIs<typename CopyDecorations<T, Plain &>::type> {};
template <class T, class Plain>
struct CopyDecorations<T const &, Plain> :
TypeIs<typename CopyDecorations<T, Plain const &>::type> {};
template <class T, class Plain>
struct CopyDecorations<T &&, Plain> :
TypeIs<typename CopyDecorations<T, Plain &&>::type> {};
template <class T, class Plain>
struct CopyDecorations<T const &&, Plain> :
TypeIs<typename CopyDecorations<T, Plain const &&>::type> {};
template <class T, class Plain>
struct CopyDecorations<T[], Plain> :
TypeIs<typename CopyDecorations<T, Plain[]>::type> {};
template <class T, class Plain>
struct CopyDecorations<T const [], Plain> :
TypeIs<typename CopyDecorations<T, Plain const []>::type> {};
template <class T, class Plain, std::size_t I>
struct CopyDecorations<T [I], Plain> :
TypeIs<typename CopyDecorations<T, Plain[I]>::type> {};
template <class T, class Plain, std::size_t I>
struct CopyDecorations<T const [I], Plain> :
TypeIs<typename CopyDecorations<T, Plain const [I]>::type> {};
template <class Decorated, class Plain>
using CopyDecorations_t = typename CopyDecorations<Decorated, Plain>::type;
int main()
{
static_assert(std::is_same<GetPlainType_t<int>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int const>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int *>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int **>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int * &>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int ** &>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int const * []>, int>{}, "");
static_assert(std::is_same<GetPlainType_t<int const **[][3][5]>, int>{}, "");
static_assert(std::is_same<CopyDecorations_t<int, double>, double>{}, "");
static_assert(std::is_same<CopyDecorations_t<int const, double>, double const>{}, "");
static_assert(std::is_same<CopyDecorations_t<int *, double>, double *>{}, "");
static_assert(std::is_same<CopyDecorations_t<int **, double>, double **>{}, "");
static_assert(std::is_same<CopyDecorations_t<int[], double>, double[]>{}, "");
static_assert(std::is_same<CopyDecorations_t<int[3], double>, double[3]>{}, "");
//******************THE TESTS BELOW DO NOT WORK
//static_assert(std::is_same<CopyDecorations_t<int[][3], double>, double[][3]>{}, "");
//static_assert(std::is_same<CopyDecorations_t<int * &, double>, double * &>{}, "");
// static_assert
// (
//std::is_same<CopyDecorations_t<int const * [], double>,
// double const * []>{}, "");
// static_assert
// (std::is_same<CopyDecorations_t<int const **[][3][5], double>,
// double const **[][3][5]>{}, "");
}
Questions:
- Can I simplify the implementation?
- The tests that fail (see
main
function), how can I fix them? - In which cases (ignoring volatile and pointers to members, pointers to functions, and functions). can you think my implementation will fail?