1

I wish to modify an existing templated class. The class's template arguments are (semi) variable and I would like to use them to generate a conditional/switch/map like function body.

My compiler does not support variadic templates so the (boost) preprocessor is currently used to generate the existing class:

template <typename item0, typename item1, typename item2 ..., typename itemN>
struct myclass { /*various operations*/ };

A new function func is required that will query variables at run-time and return an object of a that is one of the template arguments.

Example:

template <typename item0, typename item1, typename item2 ...>
struct my_class { 

    //...various operations

    //automatic generatation possible?
    std::string * func()
    {
        string s;
        while(data) {

        switch (data[0])
        {
            case item0::id:
                s += item0::get_name();
            case item1::id:
                s += item1::get_name();
            //... for each template arguemnt typename where typename is no void
        }
        }
        return s;
    }
 };

typedef my_class<a, b, c> class_one;
typedef my_class<d, e, f> class_two;
typedef my_class<a, b, c, x, y, z>  class_three;

 int main()
 {
    ...
    class_one test;
    test.func();
    ...
 }

I would like to generate the contents of func() because the number of items will be numerous, and the number of types of "myclass" will be even higher.

Can someone give me an idea of how any techniques that could accomplished this?

I already have a dependency on boost. My compiler is reasonably new (but does not support variadic templates). I would prefer not to take any new dependencies or introduce more complexity than necesssary.

MW_dev
  • 2,146
  • 1
  • 26
  • 40

2 Answers2

4

I've written code like this before, so I can tell you it is possible. (It was for commercial, closed-source work, so I'm afraid I can't show you the code). You can find a really good example of how to do this in the Boost.Variant library, in particular http://svn.boost.org/svn/boost/trunk/boost/variant/detail/visitation_impl.hpp . The code is very dense and advanced C++, so it might take a day or two to understand it thoroughly.

A quick summary: the boost::variant class template works like a union with an int storing which member of the union is valid. The "visitation" feature lets you supply a function object with an overloaded operator() that can take any of the possible members of the union, and it generates a switch statement that accesses the appropriate member and calls the right operator() overload on it. If you are already finding this complicated to follow, or you don't know about Boost.MPL yet, I suggest you stop reading here, read the Boost.Variant documentation, and then rewrite your class to be able to use that: the clever guys at Boost have already done the work for you. It's header-only, so if you're already using Boost there's no new dependency for you.

This file is in charge of generating the switch statement. In short, it has two alternative implementations. The first one (lines 72-90) uses a recursive template visitation_impl_step that works like the factorial function you might have seen as a template meta-programming example. The unspecialized template recursively calls the next one in the list (typename mpl::next<Iter>::type). The resulting code, once all the templates are expanded out, looks a bit like a series of functions function0, function1, &c. like this:

result_type functionN(variant vnt, visitor vr) {
    if (v.which == N)
        return vr(static_cast<Nth type>(vnt.value));
    else
        functionN-1(vnt, vr);
}

The second implementation (lines 193-285) uses the Boost.PP preprocessor magic library to generate a switch statement just like the one you want, with as many cases as a boost::variant can possibly have. The body of each case is a call to a template function (lines 120-185) which generates a call to the visitor on the Nth type. Most of the complexity in this implementation comes from having to worry about backing up the value inside the variant in order to preserve the strong exception guarantee if the visitor or any involved constructor throws.

Even if you decide to do it another way, I recommend reading and understanding the Boost.Variant source code, as a learning exercise. It will redefine your ideas of what is possible (and what is sensible) in C++!

Dan Hulme
  • 14,779
  • 3
  • 46
  • 95
0

Compiler will be able to generate code using exact template definition. There is no way to force compiler to generate additional cases in switch statement or additional iterations of loops depending on template parameters.

If you want to perform perform some action on instance of each type specified in template parameters you have to implement recursive template function. Please refer to this question for details.

Community
  • 1
  • 1
Goofy
  • 5,187
  • 5
  • 40
  • 56