[Home]CPPTM Answers - Exercise 2-3

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

Difference (from prior major revision) (minor diff, author diff)

Added: 167a168,223

---
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

 // (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


BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited January 6, 2008 5:39 pm (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers