【发布时间】:2019-07-18 06:00:43
【问题描述】:
我正在尝试为我的模拟器创建一个带有预编译处理函数的constexpr std::array。下面的代码适用于像0x250 这样的较小数字,但是当与最新版本的 MSVC 一起使用时,上面的所有内容都会导致“C1026 解析器溢出,程序太复杂”。
#include <array>
#include <iostream>
template<typename T>
using Executor = void(*)(T);
using IntExecutor = Executor<int>;
template<int arg>
void func(int value)
{
std::cout << (arg * value) << std::endl;
}
// Static for https://codereview.stackexchange.com/a/173570/160845
template<typename T, T Begin, class Func, T ...Is>
constexpr void static_for_impl(Func&& f, std::integer_sequence<T, Is...>)
{
(f(std::integral_constant<T, Begin + Is>{ }), ...);
}
template<typename T, T Begin, T End, class Func>
constexpr void static_for(Func&& f)
{
static_for_impl<T, Begin>(std::forward<Func>(f), std::make_integer_sequence<T, End - Begin>{ });
}
template<int N>
constexpr std::array<IntExecutor, N> makeLut()
{
std::array<IntExecutor, N> lut = { };
static_for<size_t, 0, N>([&](auto x) {
lut[x] = func<x>;
});
return lut;
}
// 0x250 works just fine
// 0x300 causes a "C1026 parser overflow, program too complex" error
constexpr auto lut = makeLut<0x250>();
int main(int argc, char* argv[])
{
int instruction = 0xDEADBEEF;
int instructionHash = instruction & 0x24F;
lut[instructionHash](instruction);
return 0;
}
我需要一个大小为0x1000 的std::array。我可以通过使用从0 到0x250 的4 更小的static_for() 循环来实现这一点,但我觉得这是一个丑陋的解决方案。
有人知道用模板函数填充constexpr std::array 的正确方法吗?
【问题讨论】:
-
有点离题,但要拥有 0x1000 大小,您不需要 4 个,而是 7-8 个大小为 0x250 的数组。回到主题,您是否尝试过任何其他编译器? PS:你确定你真的需要
constexpr数组吗?因为在运行时初始化的const似乎就足够了。 -
@sklott 哎呀,忘了我正在使用十六进制。代码使用 g++ 编译得很好。是的,我需要一个 constexpr,否则我将无法在我的数组中存储
func<x>(afaik)。 -
这是哪个版本的 C++?在 C++20 中,
array::fill是constexpr,所以你可以改用它。 -
@RadosławCybulski 数组填充对整个数组使用一个值。我希望传递的函数根据当前循环索引而有所不同,因此
func<x>。 -
好的,我现在明白了。它也可以用 clang 编译。也许更改您的
static_for实现以使用树结构?递归地将范围分成两半,然后向左执行,然后向右执行,直到范围大小为 1,在哪里执行函数本身?
标签: c++ variadic-templates template-meta-programming constexpr stdarray