不完全为整型的结构和枚举

Structs and enumerations with not-exactly-integral type

本文关键字:枚举 结构 整型 不完全      更新时间:2023-10-16

现在我知道以下是如何工作的:

template<std::uint8_t num>
struct factorial 
{
    static_assert(num <= 20, "Integer overflow!!");
    enum { value = num * factorial<num - 1>::value };
};
template <>
struct factorial<0> 
{
    enum { value = 1 };
};

它在编译时使用递归计算数字的阶乘!

您可以这样调用此函数:std::cout << factorial<20>::value;

很漂亮,但一个enum只能容纳整数类型(最多为std::uintmax_t)。这意味着我们不能计算一个大于20的数的阶乘。

现在我已经编写了一个不错的bigint小类,它删除了边界。

考虑以下内容:

template<std::uintmax_t num>
struct factorial
{
    static bigint value()
    {
        bigint result("1");
        for (bigint i("2"); i <= num; ++i)
            result *= i;
        return result;
    }
};

这需要我这样称呼它:std::cout << factorial<99>::value();。明显地因为这是一个函数。

我的问题是:有没有一种方法可以修改代码/函数,使其像第一个例子一样被调用,但仍然使用bigint类,我不能把它放在enum中。

首先,使用c++14,您可以将value()转换为constexpr:

template<std::uintmax_t num>
struct factorial
{
    constexpr bigint value()
    {
        bigint result(1);
        for (bigint i(2); i <= num; ++i)
            result *= i;
        return result;
    }
};
int main()
{
    static_assert(factorial<3>().value() == 6, "");
}

现在,如果你想用旧语法访问它,你可以用轻松地完成

template<std::uintmax_t num>
struct factorial
{
    constexpr static bigint calc_value()
    {
        bigint result(1);
        for (bigint i(2); i <= num; ++i)
            result *= i;
        return result;
    }
    constexpr static bigint value = calc_value();
};
...
static_assert(factorial<3>::value == 6, "");

为了举例说明,bigint就是unsigned


但是,请注意,这对bigint类提出了很大的要求,即它应该能够在编译时进行所有需要的计算,这可能会困难得多。然而,这显然是您的问题的内在要求。


UPD:刚刚注意到您的实际问题实际上并不是问编译时计算,而是问类似enum的语法。但这更容易做到:

template<std::uintmax_t num>
struct factorial
{
    static bigint calc_value()  { /* same code */  }
    static const bigint value;
};
template<std::uintmax_t num>
const bigint factorial<num>::value = factorial<num>::calc_value();

如果您要使用int(或类似的)而不是std::uintmax_t,这甚至是c++03兼容的。