Параметризованные нетиповые параметры шаблона?

Можно ли параметризовать нетиповые аргументы шаблона? Я пытаюсь сгенерировать 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');
}

1

Решение

Существует обходной путь, который использует параметры шаблона типа (через 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;
2

Другие решения

Следующее может помочь:

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