【发布时间】:2022-01-13 08:47:44
【问题描述】:
问题
我需要将整数m 的所有可能分区生成j 元素a_k 的总和,其中每个a_k 可以是-1、0 或1。这是一种确定性算法,因此它应该能够在编译时实现它。我想返回一个std::array,所有可能的组合为constexpr。
我的算法
简单明了,一共有3^j个组合。所以我们遍历所有这些并检查总和是否为m。有效组合总数为
\sum_{k=m}^{\lfloor (m+j)/2\rfloor}\binom{j}{k}\binom{jk}{km}
因此,我们可以计算数组的大小(即j 乘以上面的数字),然后简单地将我们通过蛮力获得的所有数字组合排队。
我的代码
我得到错误
错误:'sum' 的值在常量表达式中不可用 88 | if constexpr( sum == m )
但是,我看不到,sum 在编译时是如何未知的。
我该如何解决这个问题?
#include <array>
#include <iostream>
#include <utility>
/** constexpr for loop **/
template <auto Start, auto End, auto Inc, class F>
constexpr void constexpr_for(F&& f)
{
if constexpr (Start < End)
{
f(std::integral_constant<decltype(Start), Start>());
constexpr_for<Start + Inc, End, Inc>(f);
}
}
/** constexpr binomials **/
template<std::size_t n, std::size_t k>
struct Binomial
{
constexpr static std::size_t value = (Binomial<n-1,k-1>::value + Binomial<n-1,k>::value);
};
template<>
struct Binomial<0,0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n>
struct Binomial<n,0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n>
struct Binomial<n,n>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n, std::size_t k>
constexpr std::size_t binomial()
{
return Binomial<n,k>::value;
}
/** formula from the picture **/
template<std::size_t j, std::size_t m>
constexpr std::size_t n()
{
std::size_t result = 0;
constexpr_for<m, (j+m)/2+1, 1>([&result](auto k){
result += binomial<j, k>() * binomial<j-k, k-m>();
});
return result;
}
/** constexpr power function **/
template<std::size_t i, std::size_t j>
struct pow_t
{
constexpr static std::size_t value = i * pow_t<i, j-1>::value;
};
template<std::size_t i>
struct pow_t<i, 0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t i, std::size_t j>
constexpr std::size_t pow()
{
return pow_t<i, j>::value;
}
/** actual function in question **/
template<std::size_t j, std::size_t m>
constexpr std::array<int, j*n<j,m>()> integer_compositions()
{
std::array<int, j*n<j,m>()> result;
std::size_t i = 0;
constexpr_for<0, pow<3, j>(), 1>([&](auto k)
{
std::array<std::size_t, j> partition;
std::size_t sum = 0;
constexpr_for<0, j, 1>([&](auto l)
{
partition[l] = -((k/static_cast<std::size_t>(pow<3,l>()))%3-1);
sum += partition[l];
});
if constexpr( sum == m ) // line 88
{
constexpr_for<0, j, 1>([&](auto l)
{
result[j*i + l] = partition[l];
});
++i;
}
});
return result;
}
int main()
{
constexpr auto list = integer_compositions<3, 1>();
return EXIT_SUCCESS;
}
【问题讨论】:
-
std::size_t sum = 0;,显然不是constexpr。 -
@Jarod42 很公平。但是该算法是确定性的,因此应该可以在编译时知道总和。我需要如何更改代码?
-
某事沿着
constexpr std::array<std::size_t, j> partition = make_partition(k); constexpr std::size_t sum = accumulate(partition.begin(), partition.end(), 0); -
我可能遗漏了一些东西,但这些
constexpr if或constexpr_for是否有必要?常规的if和for似乎在这里应该可以正常工作。constexpr函数的意义在于您可以编写在编译时和运行时都可以工作的普通代码。辅助函数也是如此。 -
@chris 但我明确想要可以在编译时评估的代码。
标签: c++ c++17 constexpr template-meta-programming if-constexpr