Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way of selecting between variadic template functions based on an enum that is simpler than wrapping the functions in a struct?

Current code is as follows:

// header file...
enum class FuncType {
    AddTwoInts,
    SquareAnInt
};

template<FuncType F, typename... Ts>
int getValue(Ts...);

// ----------------------------------------
// cpp file...

template<FuncType F>
struct FuncHelper;

template<>
struct FuncHelper<FuncType::AddTwoInts> {
    static int func(int v1, int v2) {return v1 + v2;}
}

template<>
struct FuncHelper<FuncType::SquareAnInt> {
    static int func(int v) { return v*v; }
}

template <FuncType F, typename... Ts>
int getValue(Ts... args) {
    return FuncHelper<F>::func(args...);
}

// explicitly instantiate versions of getValue for each FuncType
// with the correct args...
template int getValue<FuncType::AddTwoInts, int, int>(int , int);
template int getValue<FuncType::SquareAnInt, int>(int)

The above can be used by include the header and then calling like

auto val = getValue<FuncType::AddTwoInts>( 3, 4 );

This is the exact interface I want but would like to do the implementation without needing to use FuncHelper or something equivalent. Is there a way to select variadic templates at compile time more directly?

Also are there any problems with the above that I am not seeing? My actual use case for the above is as a factory fuction for a struct type that is some data + an std::function.

like image 295
jwezorek Avatar asked Dec 06 '25 18:12

jwezorek


1 Answers

You can do this with SFINAE, if you just want to avoid the struct.

#include <type_traits>

enum class FuncType {
    AddTwoInts,
    MulTwoInts,
    SquareAnInt,
    ReturnAnInt
};

template<FuncType F, typename... Ts>
int getValue(Ts...);

// ----------------------------------------
// cpp file...

template<FuncType F, typename std::enable_if<F == FuncType::AddTwoInts, int>::type D>
int getValue_aux(int v1, int v2) { return v1 + v2; }

template<FuncType F, typename std::enable_if<F == FuncType::MulTwoInts, int>::type D>
int getValue_aux(int v1, int v2) { return v1 * v2; }

template<FuncType F, typename std::enable_if<F == FuncType::SquareAnInt, int>::type D>
int getValue_aux(int v) { return v * v; }

template<FuncType F, typename std::enable_if<F == FuncType::ReturnAnInt, int>::type D>
int getValue_aux(int v) { return v; }

template<FuncType F, typename... Ts>
int getValue(Ts... args)
{
    return getValue_aux<F, 0>(args...);
}

It's not possible to have multiple implementations internally without an auxiliary function, simply because they have different arity (so you need somewhere to unpack your variadic args). If all your impls had the same parameter list (or if there were a relatively small number of possible parameter list), you could simply switch on the FuncType and let the optimizer do the work of selecting the right one at compile time.

like image 147
Sneftel Avatar answered Dec 08 '25 07:12

Sneftel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!