Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute integer templated function based on run-time parameter

I often have some prototype behaviour that generates output based on some design method. I template the design method, which enables a lot of functionality I need. However, sometimes the design method is given at runtime, so I'm usually required to write a huge switch statement. It usually looks like this:

enum class Operation
{
    A, B
};


template<Operation O>
    void execute();

template<>
    void execute<A>()
    {
        // ...
    }

template<>
    void execute<B>()
    {
        // ...
    }

void execute(Operation o)
{
    switch (o)
    {
    case Operation::A: return execute<Operation::A>();
    case Operation::B: return execute<Operation::B>();
    }
}

I'm curious as to whether anyone has figured out a nice pattern for this system - the main drawbacks of this method is that one has to type out all the supported enumerations and do maintenance several places if new enumerations are implemented.

e: I should add that the reasons for messing with compile-time templates is to allow the compiler to inline methods in HPC as well as inherit constexpr properties.

e2: in effect, I guess what I'm asking is to have the compiler generate all the possible code paths using an implicit switch structure. Perhaps some recursive template magic?

like image 958
Shaggi Avatar asked Oct 09 '16 10:10

Shaggi


1 Answers

If you really want to utilize templates for this task you can use technique similar to this one.

// Here second template argument default to the first enum value
template<Operation o, Operation currentOp = Operation::A>
// We use SFINAE here. If o is not equal to currentOp compiler will ignore this function.
auto execute() -> std::enable_if<o == currentOp, void>::type
{
    execute<currentOp>();
}

// Again, SFINAE technique. Compiler will stop search if the template above has been instantiated and will ignore this one. But in other case this template will be used and it will try to call next handler.
template<Operation o, Operation currentOp = Operation::A>
void execute()
{
    return execute<o, static_cast<Operation>(static_cast<int>(currentOp) + 1)(c);
}
like image 113
Alexey Guseynov Avatar answered Oct 21 '22 01:10

Alexey Guseynov