home mail me! RSS (2.0) feed

gen_hierarchy - injecting base classes in C++

Would you like to generate a hierarchy of types on the fly using C++? Well, at least on-the-compilation-fly…

You could always use Andrei’s magnificent Loki library, or you could use my proposal, gen_hierarchy.

In short, I allow for two distinct types of hierarchies:

  1. Spine-like, with the given types protruding as maximal elements on that spine.
  2. A “simple” chain.

Let us see a sample of the former hierarchy type first:

C++:
  1. struct A {
  2.   void a() {
  3.     std::cout <<"a" <<std::endl;
  4.   }
  5. };
  6. struct B {
  7.   void b() {
  8.     std::cout <<"b" <<std::endl;
  9.   }
  10. };
  11. struct AB : generate_spine<
  12.   boost::mpl::vector<A, B>
  13. > {};
  14. AB ab;
  15. ab.a();
  16. ab.b();

This yields a hierarchy like       

  A mpl::void_
         \//
      B  g_s<>
       \//
       g_s<>
      //
     AB

The internal nodes are created by the framework, and “only” serve as the spine.

Note how the boost::mpl::vector is used, which is part of the powerful Boost.MPL library (http://www.boost.org/.) My hierarchy generator makes ample use of that library.

As can easily be seen, the injected maximal elements in the hierarchy, such as our A and B, are mutually independent. This means that code in A cannot communicate with code in A and vice versa. There are a lot of use cases where one need to communicate between two injected types.
generate_chain to the rescue!

The problem here is that the types to be injected must have “holes” in them – be “templated” in C++ lingo. Since I am using Boost.MPL, they must comply with what that library calls a template function class. Well, not really, since I defined some lifters, which “lift” a plain vanilla template up to the noble status of MPL meta function. The example above, with some inter-communication becomes:

C++:
  1. template<typename Base>
  2. struct A : Base {
  3.   void a() {
  4.     this->bar;
  5.     std::cout <<“touching base stuff from A”
  6.       <<std::endl;
  7.   }
  8. };
  9. template<typename Base>
  10. struct B : Base {
  11.   void b() {
  12.     std::cout <<“in B” <<std::endl;
  13.   }
  14. };
  15. struct AB : generate_chain<
  16.   boost::mpl::vector<quote_raw<A>,
  17.     quote_raw3<B>>,
  18.   boost::mpl::void_> {};

which creates the following hierarchy: 

                    mpl::void_
                       /
                     A<>
                     /
                   g_c<>
                   /
                 B<>
                 /
               g_c<>
               /
              AB

Every second node is a filler created by the framework, while the others are the injected types – albeit instantiations. The quote_raw3 template function creates a proper MPL meta function from the raw template. The reason for having to convert the simple templates is to assure that all entities dealt with by MPL or my framework are types, and not templates. See Boost.MPL for more information regarding the meta function class requirements.

I have already used my hierarchy generator from another library I wrote tonight, which I discuss in a future post.

Here is a test file using the hierarchy generator:

#include <iostream>
 
#include <boost/mpl/vector.hpp>
#include <boost/mpl/quote.hpp>
#include <boost/generate_hierarchy.hpp> // my proposal
 
 
//
// First a simple spine example
//
 
struct Foo {
  void hello_foo() {
    std::cout << "Hello from Foo!" << std::endl;
  }
  int foo;
};
 
struct Bar {
  void hello_bar() {
    std::cout << "Hello from Bar!" << std::endl;
  }
  int bar;
};
 
class FooBar :
  public boost::generate_spine<
    boost::mpl::vector<Foo, Bar>
  > {};
 
//
// Now a chained example, which requires MPL meta function
// classes
//
 
template <typename Base>
struct MFooT : Base {
  void hello_foo() {
    this->bar = 42;
    std::cout << "Hello from Foo, accessing FBar's fields!"
	      << std::endl;
  }
  int foo;
};
 
 
struct MFoo {
  template <typename Base>
  struct apply {
    struct type : Base {
      void hello_foo() {
	this->bar = 42;
	std::cout << "Hello from Foo, accessing FBar's fields!"
		  << std::endl;
      }
      int foo;
    };
  };
};
 

struct MBar {
  template <typename Base>
  struct apply {
    struct type : Base {
      void hello_bar() {
	std::cout << "Hello from Bar!" << std::endl;
      }
      int bar;
    };
  };
};
 
// We show how you can use a raw template, via quoting, and a
// proper meta function class
 
class MFooBar : public boost::generate_chain<
  boost::mpl::vector<boost::quote_raw1<MFooT>, MBar>
> {};
 
int main(int argc, char* argv[])
{
  FooBar foobar;
  foobar.hello_foo();
  foobar.hello_bar();
  MFooBar mfoobar;
  mfoobar.hello_foo();
  mfoobar.hello_bar();
}
 

Download this code: test_hierarchy.cpp

For your enjoyment, I attach the complete source code of the hierarchy generator.

#ifndef GENERATE_HIERARCHY_HPP
#define GENERATE_HIERARCHY_HPP
 
/*
 
File: generate_hierarchy.hpp
Author: David Bergman
Date: 2006-07-25
 
Copyright David Bergman 2006.
 
Not distributed under any specific license yet.
 
This is a utility to create a hierarchy from a
vector of types, using Boost.MPL and influenced
by Andrei Alexandrescu's work and, more specifically,
his implementation "HierarchyGenerators.h" being part
of his eminent Loki library.
 
The reason to write another generator is to leverage
the power found in MPL and use MPL-specific type
sequences.
 
*/
 
#include <boost/mpl/apply.hpp>
#include <boost/mpl/reverse_fold.hpp>
 
namespace boost {
 
  // The generator is a meta function in that it
  // takes some types and generates a new type, but
  // it is NOT a proper MPL meta function since it
  // does not comply with the syntactic requirements
  //(::type, ::apply...)

  // We deal with two scenarios:
  // 1. The types are concrete types, which are then
  //    added in a spine-like structure, with the
  //    generator construct as the spine.
  //    These base classes are then maximal elements,
  //    and do not have access to anything further up
  //    the spine.
  // 2. The types are parameterized, with a "hole"
  //    parameter where the chain of types are being
  //    built up. The instantiated types have access to
  //    stuff further up the chain. The base types are
  //    actually MPL meta function classes.

  namespace {
 
    // We define a meta function class creating a sub
    // class of two base classes, which can be either
    // regular classes, in which case we simply create
    // a common child, or one class and one
    // transformation meta function, in which case we
    // create a child class inheriting the application
    // of that meta function onto the base class

    struct inherit_two {
      template <typename Spine, typename Base>
      struct apply {
	struct type : Base, Spine {};
      };
    };
 
    struct inherit_app {
      template <typename Spine, typename Fun>
      struct apply {
	struct type : mpl::apply<Fun, Spine>::type {};
      };
    };

  } // anonymous namespace

  // The corresponding generators are called
  // "generate_spine" and "generate_chain"

  // Any ForwardSequence is welcome!

  //
  // generate_spine
  //

  template <typename ForwardSeq>
  struct generate_spine :
    mpl::reverse_fold<
      ForwardSeq, mpl::void_, inherit_two
    >::type
  {};

  //
  // generate_chain
  //

  template <typename MetFunSeq,
	    typename BaseT = mpl::void_>
  struct generate_chain :
    mpl::reverse_fold<MetFunSeq, BaseT,
		      inherit_app>::type {};
 
  //
  // Utilities to create a meta function class out
  // of a template.
  // In contrast to the 'quote' function in MPL,
  // this creates a meta function NO MATTER wether a
  // 'type' happens to be defined or not in the
  // template class.
  //
  // These utilities should NOT be here, but in MPL
  // - yes, they should be generated by a
  // preprocessor tool.
  // 
 
  template <template <typename> class Template>
  struct quote_raw1 {
    template <typename T>
    struct apply {
      typedef Template<T> type;
    };
  };
 
  template <
    template <typename, typename> class Template
  >
  struct quote_raw2 {
    template <typename T1, typename T2>
    struct apply {
      typedef Template<T1, T2> type;
    };
  };
 
  template <
    template <typename, typename, typename>
    class Template
  >
  struct quote_raw3 {
    template <typename T1, typename T2, typename T3>
    struct apply {
      typedef Template<T1, T2, T3> type;
    };
  };
 
} // namespace boost
 
#endif

Download this code: generate_hierarchy.hpp

Leave a Comment

You must be logged in to post a comment.