Использование delete для предотвращения вызова с недопустимыми значениями в C++14

Я могу использовать шаблоны и удалить средство, чтобы предотвратить вызов факториала с символьными или плавающими переменными следующим образом. Как написать функцию удаления для факториалов с отрицательными аргументами?

template <typename T>
constexpr T factorial(T n)
{
    return (n == 1 || n == 0) ? 1 : (n * factorial(n - 1));
}

constexpr float factorial(double) = delete;
constexpr char factorial(char) = delete;

int main()
{
    constexpr auto fiveFactorial = factorial(5);
    constexpr auto point5fact = factorial(0.5); // Error. Call to deleted version
    constexpr auto letter5fact = factorial('5'); // DITTO
    constexpr auto minusFact = factorial(-1); // How to prevent this using delete?
}

2 ответа

Решение

Невозможно. = delete это вещь во время компиляции, в то время как ваши аргументы не всегда известны во время компиляции.

Вы могли бы использовать unsigned параметр вместо этого и удалите все эти удаленные перегрузки, за счет невозможности вызвать вашу функцию со знаком номера, как factorial(2),

template <typename T> constexpr T factorial(T n)
{
    static_assert(std::is_unsigned_v<T> && !std::is_same_v<T, char>,
                  "Parameter type must be integral, unsigned, and not `char`.");
    return (n == 1 || n == 0) ? 1 : (n * factorial(T(n - 1)));
}

Как написать функцию удаления для факториалов с отрицательными аргументами?

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

Но так как это constexprесть другой способ - вы просто делаете функцию плохо сформированной для отрицательных входных данных в постоянном выражении. Например, бросая. Кроме того, поскольку вы пометили этот C++14, я изменяю вашу реализацию на цикл:

template <typename T>
constexpr T factorial(T n)
{
    if (n < 0) throw std::runtime_error("bad user!");

    T product = 1;
    for (T i = 2; i <= n; ++i) {
        product *= i;
    }
    return product;
}

constexpr auto good = factorial(5); // fine
constexpr auto bad = factorial(-1); // compile error because factorial(-1)
                                    // is not a valid constant expression
Другие вопросы по тегам