Topic: variadic templates


Author: "Earl Purple" <earlpurple@gmail.com>
Date: Tue, 5 Sep 2006 10:00:49 CST
Raw View
sharon.galtzur@gmail.com wrote:
> If i understand what u want is some means to generate lines like:
> template <A0> f(A0 a0)
> template <A0,A1> f(A0 a0, A1 a1) .... etc up to some configurable N
>
>
> If that the case i would suggest you check boost preprocessor library.
> This amazing library allow u to right meta-preprocessor which basically
> allows you to do these kind of magic with c++ macros.
> The advantage is that you dont need special external program but its
> all done right  in the compiler.

Actually, what happens in reality above is that a type parameter T
becomes shared_ptr<T> when passed in the constructor of the object it
is creating, unless T is of a basic type (which includes string) in
which case it is passed in by value.

In the case that T is not a basic type, it looks up the name in a table
and checks that it is of the correct type and the obj() function that
is called actually invokes createObject().
In the case that T is a basic type, it simply does a lexical
conversion.

The Binder classes are specialised templates that ensure the correct
behaviour is done for each parameter type.

My question has been answered above satisfactorily, and I await
variadic templates in the standard so I can implement as above.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "sharon.galtzur@gmail.com" <sharon.galtzur@gmail.com>
Date: Wed, 30 Aug 2006 20:56:16 CST
Raw View
If i understand what u want is some means to generate lines like:
template <A0> f(A0 a0)
template <A0,A1> f(A0 a0, A1 a1) .... etc up to some configurable N


If that the case i would suggest you check boost preprocessor library.
This amazing library allow u to right meta-preprocessor which basically
allows you to do these kind of magic with c++ macros.
The advantage is that you dont need special external program but its
all done right  in the compiler.

 Regards,
Sharon Galtzur                ]

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Mon, 21 Aug 2006 11:49:31 CST
Raw View
If variadic templates are brought into the standard, would it allow a
"fix" to this problem.

I have in my code templates that look like this (I've snipped a lot of
the detail I'd rather not reveal, it doesn't hide what I do that is
significant to this post and what I'd like to address)

template < typename TYPE, typename PARAM1, typename PARAM2, typename
PARAM3, typename BASE=TYPE >
class Builder3Params /* cut some detail */
{
protected:
    typename ParamBinder<PARAM1>::binder_type binder1;
    typename ParamBinder<PARAM2>::binder_type binder2;
    typename ParamBinder<PARAM3>::binder_type binder3;

public:
 /* more snip */
    void bindParams( /*fixed set of params for every instantiation*/)
    {
 /* more snip which declares and fills res */

        binder1.bind( theObjectLoader, res[0] );
        binder2.bind( theObjectLoader, res[1] );
        binder3.bind( theObjectLoader, res[2] );
    }
protected:
    BASE * createObject() const
    {
        return new TYPE( binder1.obj(), binder2.obj(), binder3.obj() );
    }
};

The purpose is to build an object of type TYPE that derives from BASE
and takes 3 parameters in its construction.

unfortuntely this is just one of 9 such templates, I have them going up
to 9 parameters (as well as a template for 0 parameters).

It would be nice to be able to do all this with just one template
definition for N parameters. And I'd like to do so where TYPE having a
constructor that takes 3 parameters in this case, of type PARAM1,
PARAM2, PARAM3.

In an variadic-parameter case, the programmer would, of course, have to
supply the correct parameter list in this instance with the correct
number of parameters and the correct types. I assumed that is what
variadic parameters were supposed to do but couldn't see any example of
this in the report. Now for the programmer to specify the number of
parameters is not a major deal - we know when we use this template
which one we are using. It is simply from the point of view of
maintaining the library - one template is better than 9 (or 10) and
would be "finalised" so there will never be a need for me to write
instantiations that take 10, 11, 12 etc parameters should they be
required.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Mon, 21 Aug 2006 21:28:21 GMT
Raw View
"Earl Purple" <earlpurple@gmail.com> wrote in message
news:1156178144.238727.142620@m79g2000cwm.googlegroups.com...
> If variadic templates are brought into the standard, would it allow a
> "fix" to this problem.
>
> I have in my code templates that look like this (I've snipped a lot of
> the detail I'd rather not reveal, it doesn't hide what I do that is
> significant to this post and what I'd like to address)
>
> template < typename TYPE, typename PARAM1, typename PARAM2, typename
> PARAM3, typename BASE=TYPE >
> class Builder3Params /* cut some detail */
[...]
> unfortuntely this is just one of 9 such templates, I have them going up
> to 9 parameters (as well as a template for 0 parameters).
>
> It would be nice to be able to do all this with just one template
> definition for N parameters. And I'd like to do so where TYPE having a
> constructor that takes 3 parameters in this case, of type PARAM1,
> PARAM2, PARAM3.


The easy solution to that problem is writing a simple few lines program for
automatically generating code. It will also be easier for a programmer to reason
about the design and to debug it, and it works with not so smart compilers as
well. I have a number of solutions that automatically generate code at the
pre-build stage and that proved to work very well.
I think it's time to standardize the facilities to execute code generators
during compilation, that would make it easily portable to all platforms.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Tue, 22 Aug 2006 09:48:48 CST
Raw View
"Gene Bushuyev" wrote:


>
> The easy solution to that problem is writing a simple few lines program for
> automatically generating code. It will also be easier for a programmer to reason
> about the design and to debug it, and it works with not so smart compilers as
> well. I have a number of solutions that automatically generate code at the
> pre-build stage and that proved to work very well.
> I think it's time to standardize the facilities to execute code generators
> during compilation, that would make it easily portable to all platforms.
>
-
> Gene Bushuyev (www.gbresearch.com)
> ----------------------------------------------------------------

I think someone else made a comment about pre-compile recently, i.e.
you write something in a higher-level script which is not C++ and then
auto-generate the appropriate C++. A bit like the way IDL works, I
guess, or yacc for C++.

With my exact situation above, I doubt it would be possible using
variadic templates to produce the related types
ParamBinder<T>::binder_type. It may be made possible to iterate through
the exact parameter types, but I can't see it extending to related
types (even if they can be template-typedefed so it might be
ParamBinder<T> instead of the extra binder_type). It would be possible
to modify my model by not using lazy construction, i.e .calling
bindParams and createObject in one go.

I would like to see variadic templates for straightforward factories
though. Such a factory could look something like:

template < typename T, typename BASE,  typename ...Var  >
class Factory< T > : public FactoryBase< BASE >
{
private:
   Var args;

public:
   explicit Factory( Var va ) : args( va ) {}

   T* create() const
  {
         return new T( args );
   }
};

args and va above would be expanded into the fully-typed argument list.
You would also probably want to write a function to create that
factory, so you'd want variadic arguments to template functions too. If
X is a type that derives from Y and takes a constructor X( int,
std::string ) then you'd invoke the function

make_factory< X, Y >( 25, std::string("foo") );

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Tue, 22 Aug 2006 10:20:52 CST
Raw View
Earl Purple wrote:
> If variadic templates are brought into the standard, would it allow a
> "fix" to this problem.
>
> I have in my code templates that look like this (I've snipped a lot of
> the detail I'd rather not reveal, it doesn't hide what I do that is
> significant to this post and what I'd like to address)

Yes, it's possible to use variadic templates to create a single
"BuilderParams" class template that eliminates the redundant code
below. I'm going to slice 'n' dice the code, showing how to transform
each chunk to use variadic templates.

> template < typename TYPE, typename PARAM1, typename PARAM2, typename
> PARAM3, typename BASE=TYPE >
> class Builder3Params /* cut some detail */

This can become:

  template<typename TYPE, typename BASE, typename... PARAMS>
  class BuilderParams

I've moved "BASE" before "PARAMS" because PARAMS is a template
parameter pack, and therefore needs to be at the end of the template
parameter list.

> {
> protected:
>     typename ParamBinder<PARAM1>::binder_type binder1;
>     typename ParamBinder<PARAM2>::binder_type binder2;
>     typename ParamBinder<PARAM3>::binder_type binder3;

I typically use tuples for storing multiple values, like this:

  tuple<typename ParamBinder<PARAMS>::binder_type...> binders;

> public:
>  /* more snip */
>     void bindParams( /*fixed set of params for every instantiation*/)
>     {
>  /* more snip which declares and fills res */
>
>         binder1.bind( theObjectLoader, res[0] );
>         binder2.bind( theObjectLoader, res[1] );
>         binder3.bind( theObjectLoader, res[2] );
>     }

The best way to do this is (probably!) with a "for_each" that works on
tuples, applying a function object to each value in the tuple. It's not
currently in the tuple library, but it's been used in various places.
For our purposes, we would write:

  struct do_bind {
    /* put theObjectLoader and res here */
    int res_idx;

    do_bind(/*inits*/) : /*inits*/, res_idx(0) { }

    template<typename Binder>
    void operator()(Binder& binder) {
      binder.bind(theObjectLoader, res[res_idx++]);
    }
  };

bindParams would look like this:

    void bindParams( /*fixed set of params for every instantiation*/)
    {
 /* more snip which declares and fills res */

      for_each(binders, do_bind(theObjectLoader, res));
    }

> protected:
>     BASE * createObject() const
>     {
>         return new TYPE( binder1.obj(), binder2.obj(), binder3.obj() );
>     }

Implementing this is a two-step process. The technique is described
fully in the "Bind" implementation of the variadic templates proposal,
so I'll reproduce the code here without too much comment. It's rather
long at the moment, but make_indexes would typically be factored out:

// Used to store a parameter pack of integers
template<int...> struct int_tuple {};

// make_indexes_impl is a helper for make_indexes
template<int I, typename IntTuple, typename... Types>
struct make_indexes_impl;

template<int I, int... Indexes, typename T, typename... Types>
struct make_indexes_impl<I, int_tuple<Indexes...>, T, Types...>
{
  typedef typename make_indexes_impl<I+1,
                                     int_tuple<Indexes..., I>,
                                     Types...>::type type;
};

template<int I, int... Indexes>
struct make_indexes_impl<I, int_tuple<Indexes...> > {
  typedef int_tuple<Indexes...> type;
};

// Metafunction that generates an int_tuple<0, 1, 2, /* up to */ N-1>,
where N is the number of types in Types
template<typename... Types>
struct make_indexes : make_indexes_impl<0, int_tuple<>, Types...> { };

Now to the actual interesting part. The "real work" shows up in
doCreateObject, where we extract the binders from each element of the
tuple, call their .obj() methods, and use the results as arguments to
the TYPE constructor:

template<int... Indexes>
BASE * doCreateObject(int_tuple<Indexes...>) const
{
     return new TYPE( get<Indexes>(binders).obj()... );
}

BASE* createObject() const
{
  return doCreateObject(typename make_indexes<PARAMS...>::type());
}

I'm not very happy with the need for "doCreateObject". We're currently
discussing adding a feature that would make extracting values from a
tuple *much* easier, collapsing all of this code down to:

BASE* createObject() const
{
  enum { N = sizeof(PARAMS...) };
  return new TYPE( get<0..N-1>(binders).obj()... );
}

Aside from the fact that we've moved "BASE" to the second parameter
(instead of the last), the variadic templates-based BuilderParams would
work the same way as your BuilderNParams class templates. No code
repetition required.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]