[Home]CPPTM Answers - Exercise 9-0

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

 // (by Ariel Badichi)
 #include <iostream>

 #include <boost/type_traits/is_empty.hpp>
 #include <boost/mpl/bool.hpp>

 namespace mpl = boost::mpl;

 template<typename F, bool F_empty, typename G, bool G_empty>
 class storage;

 template<typename F, typename G>
 class storage<F, false, G, false> // neither F nor G is empty
 {
 protected:
     storage(const F & f, const G & g)
     : f(f)
     , g(g)
     {
     }

     const F & get_f() { return f; }
     const G & get_g() { return g; }

 private:
     F f;
     G g;
 };

 template<typename F, typename G>
 class storage<F, false, G, true> // G is empty
     : private G
 {
 protected:
     storage(const F & f, const G & g)
     : G(g)
     , f(f)
     {
     }

     const F & get_f() { return f; }
     const G & get_g() { return *this; }

 private:
     F f;
 };

 template<typename F, typename G>
 class storage<F, true, G, false> // F is empty
     : private F
 {
 protected:
     storage(const F & f, const G & g)
     : F(f)
     , g(g)
     {
     }

     const F & get_f() { return *this; }
     const G & get_g() { return g; }

 private:
     G g;
 };

 template<typename F, typename G, bool BothEmpty?>
 class storage_both_empty;

 template<typename F, typename G>
 class storage_both_empty<F, G, false>
     : storage<F, true, G, false>
 {
 protected:
     storage_both_empty(const F & f, const G & g)
     : storage<F, true, G, false>(f, g)
     {
     }
 };

 template<typename F, typename G>
 class storage_both_empty<F, G, true>
     : private F
     , private G
 {
 protected:
     storage_both_empty(const F & f, const G & g)
     : F(f)
     , G(g)
     {
     }

     const F & get_f() { return *this; }
     const G & get_g() { return *this; }
 };

 template<typename F, typename G>
 struct use_both_as_base
 #ifdef NO_MI_EBO
     : mpl::false_
 #else
     : mpl::true_
 #endif
 {
 };

 template<typename F, typename G>
 class storage<F, true, G, true>
     : storage_both_empty<F, G, use_both_as_base<F, G>::value>
 {
 protected:
     typedef storage_both_empty<F, G, use_both_as_base<F, G>::value> base;

     storage(const F & f, const G & g)
     : base(f, g)
     {
     }
 };

 //

 template<typename R, typename F, typename G>
 class compose_fg
     : storage<F, boost::is_empty<F>::value, G, boost::is_empty<G>::value>
 {
     typedef storage<
         F, boost::is_empty<F>::value,
         G, boost::is_empty<G>::value
     > base;

 public:
     compose_fg(const F & f, const G & g)
     : base(f, g)
     {
     }

     template<typename T>
     R operator() (const T & x) const
     {
         const F & f = this->get_f();
         const G & g = this->get_g();
         return f(g(x));
     }
 };

 struct Empty
 {
     int operator() (int x) const { return x; }
 };

 struct Empty2
 {
     int operator() (int x) const { return x; }
 };

 struct Nonempty
 {
     Nonempty(int m) : m(m) {}
     int operator() (int x) const { return x + m; }
     int m;
 };

 template<typename R, typename F, typename G>
 compose_fg<R, F, G> compose(const F & f, const G & g)
 {
     return compose_fg<R, F, G>(f, g);
 }

 int main()
 {
     Nonempty nonempty(1);
     Empty empty;
     Empty2 empty2;

     std::cout << sizeof(compose<int>(nonempty, nonempty)) << "\n";
     std::cout << sizeof(compose<int>(nonempty, empty)) << "\n";
     std::cout << sizeof(compose<int>(empty, nonempty)) << "\n";
     std::cout << sizeof(compose<int>(empty2, empty)) << "\n";

     return 0;
 }

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited March 27, 2005 12:25 pm (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers