Search code examples
c++templatesc++11variadic-templatesauto-generate

Parameterized non-type template parameters?


Is it possible to parameterize non-type template arguments? I'm trying to generate a thunk that forwards its arguments to one of two compile time constant functions based on some runtime check, to get something hopefully along the lines of this:

#include <stdlib.h>

int a(int, int, char) {
    return 0;
}

int b(int, int, char) {
    return 0;
}

// This doesn't work
template<typename ReturnType, typename... Params>
template<ReturnType (*first)(Params...), ReturnType (*second)(Params...)>
ReturnType coin_flip(Params... params) {
    if (rand() % 2) {
        return first(params...);
    } else {
        return second(params...);
    }
}

int main() {
    return coin_flip<a, b>(1, 2, '3');
}

Solution

  • There is a workaround which uses type template parameters (via std::integral_constant) and macros:

    #include <type_traits>
    
    template <typename, typename>
    struct coin_flip;
    
    template
        <
            typename ReturnType,
            typename... Params,
            ReturnType (*first)(Params...),
            ReturnType (*second)(Params...)
        >
    struct coin_flip
        <
            std::integral_constant<ReturnType (*)(Params...), first>,
            std::integral_constant<ReturnType (*)(Params...), second>
        >
    {
        static
        ReturnType call(Params&&... params) {
            if (rand() % 2) {
                return first(std::forward<Params>(params)...);
            } else {
                return second(std::forward<Params>(params)...);
            }
        }
    };
    
    #define FUNCTION_CONSTANT(f) std::integral_constant<decltype(&f), f>
    
    #define COIN_FLIP(first, second, ...) \
        coin_flip<FUNCTION_CONSTANT(first), FUNCTION_CONSTANT(second)>::call(__VA_ARGS__)
    

    Example of using:

    std::cout << COIN_FLIP(a, b, 1, 2, '3') << std::endl;