// (by Ariel Badichi) #include <iostream> #include <cstddef>
#include <boost/type_traits.hpp>
template<typename T> struct bounds { static const std::size_t value = 0; };
template<typename T, std::size_t N> struct bounds<T[N]> { static const std::size_t value = N; };
template<typename T> struct type_descriptor { std::ostream & print(std::ostream & out) const { if (boost::is_volatile<T>::value) { typedef typename boost::remove_volatile<T>::type newtype; out << type_descriptor<newtype>() << " volatile"; } else if (boost::is_const<T>::value) { typedef typename boost::remove_const<T>::type newtype; out << type_descriptor<newtype>() << " const"; } else if (boost::is_pointer<T>::value) { typedef typename boost::remove_pointer<T>::type newtype; out << type_descriptor<newtype>() << " *"; } else if (boost::is_reference<T>::value) { typedef typename boost::remove_reference<T>::type newtype; out << type_descriptor<newtype>() << " &"; } else if (boost::is_array<T>::value) { typedef typename boost::remove_bounds<T>::type newtype; out << type_descriptor<newtype>() << " [" << bounds<T>::value << "]"; } else if (boost::is_same<long, T>::value) { out << "long"; } else if (boost::is_same<int, T>::value) { out << "int"; } else if (boost::is_same<short, T>::value) { out << "short"; } else if (boost::is_same<char, T>::value) { out << "char"; } else { out << "unknown"; }
return out; } };
template<typename T> std::ostream & operator<< (std::ostream & out, const type_descriptor<T> & desc) { return desc.print(out); }
int main() { std::cout << type_descriptor<int>() << "\n" << type_descriptor<char *>() << "\n" << type_descriptor<long const * &>() << "\n" << type_descriptor<short[10]>() << "\n" << type_descriptor<volatile int>() << "\n";
return 0; }
// by HSH // There is very small problem. std::cout << type_descriptor<int[2][3]>() << std::endl; // prints int[3][2]... // I think it can be fixed by introducing something likes 'bound_descriptor'. // However, that's not an elegant solution.
// by Nicolas Haller <nicolas@boiteameuh.org> // A solution only to the exercise (but extendable) inspired by the solution // of Ariel Badichi. I sure there is (a lot of) room for improvement // (if it's not completely wrong)so feel free to modify my solution :-)
#include <iostream>
// Primary template which produce compiler error if instantiated
template <class T> struct type_descriptor { };
// Specialization template for "basic" type template <> struct type_descriptor<int> { static std::ostream & print(std::ostream & ost) { return ost << "int"; } };
template <> struct type_descriptor<long> { static std::ostream & print(std::ostream & ost) { return ost << "long"; } };
template <> struct type_descriptor<char> { static std::ostream & print(std::ostream & ost) { return ost << "char"; } };
// Specialization template about qualifiers and pointers/references template <class T> struct type_descriptor<T*> { static std::ostream & print(std::ostream & ost) { return type_descriptor<T>::print(ost) << " *"; } };
template <class T> struct type_descriptor<T&> { static std::ostream & print(std::ostream & ost) { return type_descriptor<T>::print(ost) << " &"; } };
template <class T> struct type_descriptor<const T> { static std::ostream & print(std::ostream & ost) { ost << " const "; return type_descriptor<T>::print(ost); } };
// Template function which doesn't need any specialization template <class T> std::ostream & operator<<(std::ostream & ost, const type_descriptor<T> & tdesc) { return type_descriptor<T>::print(ost); }
// entry point int main() { std::cout << type_descriptor<int>() << std::endl; std::cout << type_descriptor<char *>() << std::endl; std::cout << type_descriptor<long const * &>() << std::endl;
return 0; }
--- IMHO: In order to get multiple dimensions working with arrays I changed the code:
else if (boost::is_array<T>::value) { typedef typename boost::remove_bounds<T>::type newtype; out << type_descriptor<newtype>() << " [" << bounds<T>::value << "]"; }
to look like this (more or less fixing variable names etc to match Ariel Badichi's code above):
else if (boost::is_array<T>::value) { const unsigned rank=boost::rank<T>::value; typedef typename boost::remove_extent<T, rank-1>::type slice; out << type_descriptor<slice>() << "[" << boost::extent<T, rank-1>::value << "]"; }
Unfortunately, I couldn't find a way to make the boost::remove_extent<> allow the removal of the least significant rank because it has no template parameter for doing this.
ex: boost::remove_extent<T /*, rank-1 */> // so sad
This may have worked if boost allowed it, but I couldn't get it to compile.
So, as an alternative, I constructed a private recursive helper function:
private: template<typename Array> void put_extents(std::ostream& out) const { out << "[" << boost::extent<Array>::value << "]"; typedef typename boost::remove_extent<Array>::type slice; if (boost::is_array<slice>::value) { put_extents<slice>(out); } }
and instead called it like so:
else if (boost::is_array<T>::value) { typedef typename boost::remove_all_extents<T>::type no_extents; out << type_descriptor<no_extents>(); put_extents<T>(out); }
seemed to fix that problem for me. FYI
Mitch Besser bessermt at gmail dot com