Specify template parameters at runtime

If macros aren't your thing then you can also generate the if-then-else's using templates:

#include <stdexcept>
#include <iostream>

const unsigned int END_VAL = 10;

class MyClassInterface
{
public:
    virtual double foo (double) = 0;
};

template<int P1, int P2, int P3>
class MyClass : public MyClassInterface
{
public:
    double foo (double a)
    {
        return P1 * 100 + P2 * 10 + P3 + a;
    }
};

struct ThrowError
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        throw std::runtime_error ("Could not create MyClass");
    }
};

template<int DEPTH = 0, int N1 = 0, int N2 = 0, int N3 = 0>
struct Factory : ThrowError {};

template<int N2, int N3>
struct Factory<0, END_VAL, N2, N3> : ThrowError {};

template<int N1, int N3>
struct Factory<1, N1, END_VAL, N3> : ThrowError {};

template<int N1, int N2>
struct Factory<2, N1, N2, END_VAL> : ThrowError {};

template<int N1, int N2, int N3>
struct Factory<0, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c1 == N1)
            return Factory<1, N1, 0, 0>::create (c1, c2, c3);
        else
            return Factory<0, N1 + 1, N2, N3>::create (c1, c2, c3);
    }
};

template<int N1, int N2, int N3>
struct Factory<1, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c2 == N2)
            return Factory<2, N1, N2, 0>::create (c1, c2, c3);
        else
            return Factory<1, N1, N2 + 1, N3>::create (c1, c2, c3);
    }
};

template<int N1, int N2, int N3>
struct Factory<2, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c3 == N3)
            return new MyClass<N1, N2, N3> ();
        else
            return Factory<2, N1, N2, N3 + 1>::create (c1, c2, c3);
    }
};

MyClassInterface* factory (int c1, int c2, int c3)
{
    return Factory<>::create (c1, c2, c3);
}

Since the tests are nested it should be more efficient than sharth's macro solution.

You can extend it to more parameters by adding more depth cases.


Here's what you can do:

MyClassInterface* Factor(int p1, int p2, int p3) {
  if (p1 == 0 && p2 == 0 && p3 == 0)
    return new MyClass<0,0,0>();
  if (p1 == 0 && p2 == 0 && p3 == 1)
    return new MyClass<0,0,1>();
  etc;
}

Note that this does not even remotely scale to floating point values. It scales only to a known list of discrete values.


I've also used this bit of code before to do some template automatic generation:

#include <boost/preprocessor.hpp>

#define RANGE ((0)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12))
#define MACRO(r, p) \
    if (BOOST_PP_SEQ_ELEM(0, p) == var1 && BOOST_PP_SEQ_ELEM(1, p) == var2 && BOOST_PP_SEQ_ELEM(2, p) == var3 && BOOST_PP_SEQ_ELEM(3, p) == var4) \
        actual_foo = foo<BOOST_PP_TUPLE_REM_CTOR(4, BOOST_PP_SEQ_TO_TUPLE(p))>;
BOOST_PP_SEQ_FOR_EACH_PRODUCT(MACRO, RANGE RANGE RANGE RANGE)
#undef MACRO
#undef RANGE

The compiler produces output that looks like this:

if (0 == var1 && 0 == var2 && 0 == var3 && 0 == var4) actual_foo = foo<0, 0, 0, 0>;
if (0 == var1 && 0 == var2 && 0 == var3 && 1 == var4) actual_foo = foo<0, 0, 0, 1>;
if (0 == var1 && 0 == var2 && 0 == var3 && 2 == var4) actual_foo = foo<0, 0, 0, 2>;
if (0 == var1 && 0 == var2 && 0 == var3 && 3 == var4) actual_foo = foo<0, 0, 0, 3>;
if (0 == var1 && 0 == var2 && 0 == var3 && 4 == var4) actual_foo = foo<0, 0, 0, 4>; 
if (0 == var1 && 0 == var2 && 0 == var3 && 5 == var4) actual_foo = foo<0, 0, 0, 5>;
if (0 == var1 && 0 == var2 && 0 == var3 && 6 == var4) actual_foo = foo<0, 0, 0, 6>;
if (0 == var1 && 0 == var2 && 0 == var3 && 7 == var4) actual_foo = foo<0, 0, 0, 7>;
if (0 == var1 && 0 == var2 && 0 == var3 && 8 == var4) actual_foo = foo<0, 0, 0, 8>;
etc...

Also, please note that with this method, with 4 variables, each ranging over 13 values, You would cause the compiler to instantiate 28561 copies of this function. If your n was 50, and you still had 4 options, you would have 6250000 functions instantiated. This can make for a SLOW compile.


Thats not posible, templates are instantiated at compile time.
By the time you have an executable you only have classes(particular instantiations of those templates), no templates any more.

If you don't know values at compile time you can't have templates for those.

Tags:

C++

Templates