Рекурсия во время компиляции с SFINAE в качестве аргумента шаблона - PullRequest
0 голосов
/ 06 февраля 2020

Я играл с шаблонами и хотел использовать их для написания рекурсивной функции, которая будет оцениваться во время компиляции. И я хочу, чтобы это ветвилось в зависимости от числа, которое я передаю ему. Функция имеет ограничение; Я хочу сохранить возвращаемое значение.

Итак, это была моя попытка написать функцию (она не компилируется):

template<int n, typename std::enable_if_t<n==1>>
constexpr auto fun() { return std::make_tuple(1); }

template<int n, typename std::enable_if_t<n==2>>
constexpr auto fun() { return std::make_tuple(fun<1>(), 2); }

template<int n, typename enable = void>
constexpr auto fun() {
    return std::tuple_cat(fun<n-1>(), n);
}

int main() {
    constexpr auto x = fun<4>();

    return 0;
}

Проблема, с которой я сталкиваюсь, заключается в том, что я Я не уверен, куда поместить оператор std::enable_if_t и как его написать, чтобы убедиться, что моя функция правильно разветвляется. Что мне здесь не хватает?

Ответы [ 2 ]

3 голосов
/ 07 февраля 2020

Предполагая, что вы хотите объединить свой кортеж и создать его в виде

fun<4>() == tuple(1, 2, 3, 4);

, вы можете написать два шаблона, например

template<int n, std::enable_if_t<n == 1>* = nullptr>
constexpr auto fun() 
{
    return std::make_tuple(1); 
}

template<int n, std::enable_if_t<n != 1>* = nullptr>
constexpr auto fun()
{
    return std::tuple_cat(fun<n-1>(), std::tuple(n));
}

Однако это не " C ++ 17 способ " сделать это. Это можно выразить гораздо лучше, используя if constexpr

template<int n>
constexpr auto fun2()
{
    if constexpr (n > 1)
        return std::tuple_cat(fun2<n-1>(), std::tuple(n));
    else
        return std::tuple(1);
}

Что касается создания последовательности (например, 1, 2, 3, 4, ...), существует также std::integer_sequence, который можно использовать в сочетании с шаблоном пакеты параметров

template <int... nums>
constexpr auto construct(std::integer_sequence<int, nums...>)
{
    return std::tuple((nums + 1)...);
}

template<int n>
constexpr auto fun3()
{
    return construct(std::make_integer_sequence<int, n>());
}

Здесь - полный пример.

2 голосов
/ 07 февраля 2020

Непонятно для меня, что именно вы хотите, но ... позвольте мне угадать: вы хотите что-то, как указано ниже шаблон класса, где есть основная версия и некоторая специализация; поэтому основная версия определяет сигнатуру и специализации, которые SFINAE включает / отключает с помощью std::enable_if.

С функциями у вас есть перегрузка функций, но не частичная специализация. Вы должны включить / отключить каждую перегруженную функцию самостоятельно

template<int n, std::enable_if_t<n==1, bool> = true>
// ...

template<int n, std::enable_if_t<n!=1, bool> = true>
// ...

Заметьте, что я написал

template<int n, std::enable_if_t<n==1, bool> = true>

, а не

template<int n, typename = std::enable_if_t<n==1>>

Вторая форма также работает включить / отключить одну функцию, но она не работает, если у вас разные функции с одинаковой сигнатурой (как в вашем случае) и вы хотите включить только одну версию.

...