参数化非类型模板参数?

时间:2014-04-06 09:31:09

标签: c++ templates c++11 variadic-templates auto-generate

是否可以参数化非类型模板参数?我正在尝试生成一个thunk,它根据一些运行时检查将其参数转发给两个编译时常量函数之一,以获得有希望的东西:

#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');
}

3 个答案:

答案 0 :(得分:2)

有一种解决方法,它使用类型模板参数(通过std::integral_constant)和宏:

#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__)

使用示例:

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

答案 1 :(得分:0)

以下可能会有所帮助:

template<typename F, F f1, F f2, typename... Params>
auto coin_flip(Params&&... params) -> decltype(f1(std::forward<Params>(params)...)) {
    if (rand() % 2) {
        return f1(std::forward<Params>(params)...);
    } else {
        return f2(std::forward<Params>(params)...);
    }
}

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

答案 2 :(得分:0)

您可以将函数作为参数传递给coin_flip(而不是模板参数):

#include <iostream>
#include <cstdlib>
#include <type_traits>

int a(int, int, char) {
    std::cout << 'a';
    return 0;
}

int b(int, int, char) {
    std::cout << 'b';
    return 0;
}

template<typename FnA, typename FnB, typename... Params>
typename std::result_of<FnA&(Params...)>::type
coin_flip(FnA a, FnB b, Params... params) {
    // For testing, the condition is removed here
    a(params...);
    return b(params...);
}

int main() {
    coin_flip(a, b, 1, 2, '3');
    std::cout << '\n';
    return  0;
}