Passing any function as a template parameter?

2020-07-25 04:57发布

问题:

I am looking for a way to pass a generic (constexpr, obviously) function to a template. It has to be able to take any amount of parameters, without using a lambda. This is what I have so far:

template<typename T, T(*FUNC)()> struct CALL
{
    static inline constexpr decltype(FUNC()) EXEC()
    {
        return FUNC();
    }
};

This however only works if the passed function takes no parameters. Is there a way to make the template accept ANY constexpr function? Passing a std::function does not seem to work. I suppose the key is variadic template parameters, but I have no idea how to take advantage of them in this situation.

回答1:

If I understand correctly what you are trying to achieve, you can use a template function rather than a template class with a static function:

#include <iostream>

template<typename T, typename... Ts>
constexpr auto CALL(T (*FUNC)(Ts...), Ts&&... args) -> decltype(FUNC(args...))
{
    return FUNC(std::forward<Ts>(args)...);
}

constexpr double sum(double x, double y)
{
    return (x + y);
}

int main()
{
    constexpr double result = CALL(sum, 3.0, 4.0);
    static_assert((result == 7.0), "Error!");
    return 0;
}


回答2:

template<int... I>
struct with
{
    template<int F(decltype(I)...)>
    struct call
    {
        static constexpr int value = F(I...);
    };
};

constexpr int f(int i) {return i;}
constexpr int g(int i, int j) {return i + j;}

int main()
{
    int u = with<0>::call<f>::value;
    constexpr int v = with<0, 1>::call<g>::value;
}

Note, this has some of the limitations as in your previous question which I answer with std::integral_constant. But a constexpr double value could still be generated from non-type template arguments at compilation time.

#include <iostream>

template<typename T, T... v>
struct with
{
    template<typename R, R f(decltype(v)...)>
    struct call
    {
        static constexpr R value = f(v...);
    };
};

#define AT_COMPILATION(f, x, ...) with<decltype(x), x, ##__VA_ARGS__>::call<decltype(f(x, ##__VA_ARGS__)), f>::value

constexpr long f(long i) {return i;}
constexpr double g(int i, int j) {return static_cast<double>(i) / j;}

int main()
{
    constexpr double u = with<long, 0L>::call<decltype(f(0L)), f>::value;

    std::cout << with<int, 5, 2>::call<double, g>::value << std::endl;

    constexpr double v = AT_COMPILATION(f, 0L);

    std::cout << AT_COMPILATION(g, 5, 2) << std::endl;
}