Re: [boost] Generic object construction

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Eric Niebler Sent: Monday, September 25, 2006 11:00 AM To: Boost mailing list Subject: [boost] Generic object construction
I have come up with a little generic object construction utility using Boost.Parameter that works for me. It allows you to non-intrusively associate named parameters with a type for the purpose of construction, and a way to forward a (possibly filtered) argument pack on to sub-objects. Is there general interest in such a utility?
This sounds like it would be generally useful for factory functions as well... Is that true? Thanks, Sohail

Sohail Somani wrote:
[mailto:boost-bounces@lists.boost.org] On Behalf Of Eric Niebler
I have come up with a little generic object construction utility using Boost.Parameter that works for me. It allows you to non-intrusively associate named parameters with a type for the purpose of construction, and a way to forward a (possibly filtered) argument pack on to sub-objects. Is there general interest in such a utility?
This sounds like it would be generally useful for factory functions as well... Is that true?
Well, it *is* a factory function, but a generic one. OK, there seems to be interest. Here's an dumb example, involving a facade that associates a name with an object: template<typename Object> struct named_facade { typedef Object object_type; named_facade( /*TODO*/ ) : object_( /*TODO*/ ) , name_( /*TODO*/ ) {} private: Object object_; std::string name_; }; Now, we want a named vector: template<typename T> struct named_vector : named_facade<std::vector<T> > { named_vector( size_t size , std::string name , T const & value = T() ) : named_facade<std::vector<T> >( /*TODO*/ ) {} }; First, we define named parameters for use when constructing a std::vector: BOOST_PARAMETER_KEYWORD(tag, size) BOOST_PARAMETER_KEYWORD(tag, value) And we hook the factory for std::vector: namespace boost { namespace constructors { namespace impl { struct std_vector_tag; template<typename T, typename Al> struct tag<std::vector<T,Al> > { typedef std_vector_tag type; }; template<typename T> struct construct<T, std_vector_tag> { typedef parameter::parameters< parameter::required<tag::size> , parameter::optional<tag::value> > args_type; typedef T result_type; template<typename Args> T operator()(Args const &args) const { return T(args[size], args[value | typename T::value_type()]; } }; }}} With that, we can now construct a vector with: constructors::construct<std::vector<int> >( size = 10, value = 42); Nothing too exciting, yet. Next, we specify the constructor arguments to named_facade< >: // first, define a keyword for the name parameter BOOST_PARAMETER_KEYWORD(tag, name) namespace boost { namespace constructors { namespace impl { struct named_facade_tag; template<typename Object> struct tag<named_facade<Object> > { typedef named_facade_tag type; }; template<typename T> struct construct<T, named_facade_tag> : constructors::arg_pack_construct { // NOTE: by inheriting from arg_pack_constructor, the // construct<named_facade<...> >(...) function will return an // argument pack instead of a named_facade<>. We will define // a named_facade<> constructor that takes an argument pack. typedef typename T::object_type object_type; // TODO: what we really want here is to insert the "name" // keyword into object_type's parameter spec, but we can't // do that yet because parameters<> is not an MPL sequence: typedef typename construct<object_type>::args_type args_type; }; }}} Now, we can complete the implementation of named_facade: template<typename Object> struct named_facade { typedef Object object_type; template<typename ArgPack> named_facade( ArgPack const & args ) : object_( // forwards the args to Object's c'tor constructors::forward_construct<Object>(args) ) , name_( args[ name | "<noname>" ] ) {} private: Object object_; std::string name_; }; Finally, the named_vector constructor looks like: template<typename T> struct named_vector : named_facade<std::vector<T> > { typedef named_facade<std::vector<T> > base_type; named_vector( size_t size_ , std::string name_ , T const & value_ = T() ) : base_type( constructors::construct<base_type>( size = size_ , value = value_ , name = name_ ) {} }; Basically, you define specialization of the construct<> template that either: A) returns a fully constructed T object via the associated named parameters, or B) returns an argument pack, assuming T has a constructor that accepts an argument pack. (A) is useful when we must make an existing type fit into the framework. (B) is useful when we must pass constructor arguments through to sub-objects, or when in-place construction is important (eg., if the object is expensive to copy, or is noncopyable) The code lives at http://tinyurl.com/hoowm for now. -- Eric Niebler Boost Consulting www.boost-consulting.com
participants (2)
-
Eric Niebler
-
Sohail Somani