[Home]CPPTM Answers - Exercise 9-1

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

 
 // (by Ariel Badichi)
 #include <iostream>
 
 #include <boost/type_traits/is_empty.hpp>
 #include <boost/type_traits/is_same.hpp>
 #include <boost/mpl/bool.hpp>
 #include <boost/mpl/not.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 NotSame>
 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::not_<boost::is_same<F, G> >
 #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";
     std::cout << sizeof(compose<int>(empty, empty)) << "\n";
 
     return 0;
 }

I haven't done 9-0, yet, so ignoring any mechanism needed for that, can't you solve 9-1 by just adding a specialization for the storage class that looks like this:

 
	template <class F>
	class storage<F,true,F,true> // same empty class used twice
		: private F
	{
	protected:
		storage(F const& f, F const& g)
			: F(f)
		{}
		F const& get_f() const { return *this; }
		F const& get_g() const { return *this; }
	};


Now, obviously you're throwing away the second parameter passed in here, but if it's an empty class (therefore has no state) of the exact same type (so no "state" embedded in the type different from F,) then that should be safe to do, right?

As far as I can see, this is safe. Good thinking! - Ariel


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