Boost logo

Boost Users :

From: Paul Mensonides (yg-boost-users_at_[hidden])
Date: 2002-12-19 02:56:24


"Tanton Gibbs" <thgibbs_at_[hidden]> wrote in message
news:024e01c2a725$6814d720$b048cc18_at_Corp.Acxiom.net...
> I'm trying to create a template class based on user input. For example:
>
> template< int i, int j, int k > class T {};
>
> int main() {
> int i, j, k;
> cin >> i >> j >> k;
> T<i, j, k> t;
> }
>
> Naturally, this is not possible, as i, j, and k must be constants.
Therefore, I would like to limit the maximum value of i, j, and k to 100 and
create all permutations for T<i,,j,k> at compile time. Basically, something
like this:

Hi Tanton,

You realize that this will give you a 101*101*101 permutation right? While
the pp-lib can generate it, that is a pretty big block of code to be inside
a single function. I would try to separate it into separate functions if
possible:

template<int i, int j, int k> struct bound {
    static void target() {
        T<i, j, k> t;
        // ...
    }
};

typedef void (* pf)();

template<int i, int j> pf bind(int k) {
    switch (k) {
        case 0:
            return &bound<i, j, 0>::target;
            break;
        case 1:
            return &bound<i, j, 1>::target;
            break;

        // ...

        default:
            return 0;
    }
}

template<int i> pf bind(int j, int k) {
    switch (j) {
        case 0:
            return bind<i, 0>(k);
        case 1:
            return bind<i, 1>(k);

        // ...

        default:
            return 0;
    }
}

pf bind(int i, int j, int k) {
    switch (i) {
        case 0:
            return bind<0>(j, k);
        case 1:
            return bind<1>(j, k);

        // ...

        default:
            return 0;
    }
}

int main() {
    int i, j, k;
    std::cin >> i >> j >> k;
    bind(i, j, k)();
    // ...
}

Will something like that work for you? Something similar to this is *way*
better than having an if structure with 101*101*101 conditional tests. If
so, here is an implementation:

#include <iostream>
#include <boost/preprocessor/iteration/local.hpp>

#define LIMIT 100

template<int i, int j, int k> struct bound {
    static void target() {
        std::cout << i << ' ' << j << ' ' << k << &std::endl;
        return;
    }
};

void overflow() {
    std::cout << "overflow" << &std::endl;
    return;
}

typedef void (* pbound_f)();

template<int i, int j> pbound_f bind(int k) {
    switch (k) {
        #define BOOST_PP_LOCAL_MACRO(k) \
            case k: \
                return &bound<i, j, k>::target; \
            /**/
        #define BOOST_PP_LOCAL_LIMITS (0, LIMIT)
        #include BOOST_PP_LOCAL_ITERATE()
        default:
            return &overflow;
    }
}

template<int i> pbound_f bind(int j, int k) {
    switch (j) {
        #define BOOST_PP_LOCAL_MACRO(j) \
            case j: \
                return bind<i, j>(k); \
            /**/
        #define BOOST_PP_LOCAL_LIMITS (0, LIMIT)
        #include BOOST_PP_LOCAL_ITERATE()
        default:
            return &overflow;
    }
}

pbound_f bind(int i, int j, int k) {
    switch (i) {
        #define BOOST_PP_LOCAL_MACRO(i) \
            case i: \
                return bind<i>(j, k); \
            /**/
        #define BOOST_PP_LOCAL_LIMITS (0, LIMIT)
        #include BOOST_PP_LOCAL_ITERATE()
        default:
            return &overflow;
    }
}

int main() {
    int i, j, k;
    std::cin >> i >> j >> k;
    bind(i, j, k)();
    return 0;
}

This works, but takes forever to compile--at least on Comeau C++. The
reason is not the use of the pp-lib though (that is fast), it is because of
the sheer amount of template instantiations. E.g. you get 101
instantiations of the one-template-argument "bind," 10,201 instantiations of
the two-template-argument "bind," and 1,030,301 instantiations of the
"target" function (+ 1,030,301 instantiations of "T"). Even if you use the
"if/else if" statements (or nested switches), you still going to get
instantiations of "T" in the millions. That means that you have to 1) bite
the bullet and give up trying to do whatever you're doing with compile-time
values or 2) seriously reduce the maximum value (to about 10, for example).
In any case, the pp-lib can generate this, direct nested switches, or even
the permutations along the lines of "if/else if." The problem is massive
instantiation and massive code bloat no matter how you do it. IMHO, it just
isn't worth it.

Another idea is to have an array of function pointers:

pbound_f array[101][101][101] = { ... };

...and initialize the elements with instantiations of some fully bound
function template (the pp-lib can, of course, do this as well). And use it
like this:

array[i][j][k]();

This will only avoid the first 10,302 instantiations though. You are still
going to get template instantiation in the millions. What are you trying to
do exactly? Maybe there is a better way.

> Naturally, I don't want to type all that in myself, so I was hoping the
boost preprocessor library could do it for me. If someone knows of a way to
do it, please let me know.

Regards,
Paul Mensonides


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net