如何在MSVC中允许更高的模板递归限制?

How to allow higher template recursion limit in MSVC?

提问人:Julien BERNARD 提问时间:10/7/2023 最后编辑:Jarod42Julien BERNARD 更新时间:10/11/2023 访问量:93

问:

我正在用 C++ 编写模板元编程代码,以生成用于嵌入式编程目的的查找表(缺少 FPU)。我一直在使用 MSVC 进行原型设计。

尝试生成最终的 128x128,每个单元格 LUT 2 个字节时,我收到错误 C1202:递归类型或函数依赖关系上下文太复杂。

但是对于 100x100,它会在几秒钟内生成,一切都很好。我无法找到如何在 Web 上的 MSVC 中增加模板递归限制。

根据 2014 年的这个问题,问同样的事情,Visual C++ - 设置模板实例化的深度,没有,但我希望事情已经发生了变化,这里有人可能知道它。

下面是上下文代码:

const size_t tableSize = 128;
const float unit = 80.;
using Cell = std::pair<uint8_t, uint8_t>;

constexpr auto f = [](uint8_t x, uint8_t y) -> Cell {
    float _x = x / unit;
    float _y = y / unit;

    float norm2 = std::sqrt(_x * _x + _y * _y);
    float norm2Min1 = norm2 < 1 ? 1 : norm2;
    return {(uint8_t)(x / norm2Min1), (uint8_t)(y / norm2Min1) };
};

template<uint8_t rowNo, uint8_t columnNo> struct Row {
    Cell cell = f(columnNo, rowNo);
    Row<rowNo, columnNo + 1> rest;
};
template<int rowNo> struct Row<rowNo, tableSize-1> {
    Cell cell = f(tableSize-1, rowNo);
};

template<int rowNo> struct Table {
    Row<rowNo, 0> row;
    Table<rowNo + 1> rest;
};
template<> struct Table<tableSize-1> {
    Row<tableSize-1, 0> row;
};

struct LUT {
    Table<0> table;

    Cell precomputedF(uint8_t x, uint8_t y) {
        return ((Cell*)(&table))[y * tableSize + x];
    }
};

int main()
{
    LUT lut;
    int size = sizeof(LUT);

    std::cout << size << "\n\n";

    for (int x = 0; x < tableSize; x++) {
        for (int y = 0; y < tableSize; y++) {
            auto result = lut.precomputedF(x, y);
            std::cout << "(" << (int)result.first << "," << (int)result.second << ")" << " ";
        }
        std::cout << "\n";
    }
}
C visual-c++ 模板-元编程 查找表

评论

0赞 tadman 10/7/2023
Windows 上的堆栈通常非常精简,这意味着您需要小心使用大型数组或大量小型数组来占用堆栈空间。你能显示上下文代码吗
0赞 Julien BERNARD 10/7/2023
嘿@tadman,刚刚添加了代码。
2赞 NathanOliver 10/7/2023
我会首先尝试放弃递归,而是使用 constexpr/conteval 函数来生成 LUT。然后,您可以使用 for 循环而不是递归。
1赞 Eljay 10/7/2023
我使用的另一种方法是编写一个程序来执行所有繁重的计算,并将结果输出为 C 代码——作为预先计算的数据数组——我可以在我的 C 代码中输出。(已经有一段时间了。在我学习 C++ 之前,所以 1980 年代。#include
1赞 Jarod42 10/7/2023
“如何在MSVC中允许更高的模板递归限制?”一种解决方法(对于一般情况)是显式实例化一些中间实例。

答:

3赞 Mooing Duck 10/7/2023 #1

不要使用模板。用constexpr

using Table = std::array<std::array<Cell, tableSize>, tableSize>;
consteval Table make_LUT() {
    Table table;
    for(size_t x=0; x<tableSize; x++) {
        for(size_t y=0; y<tableSize; y++)
            table[y][x] = f(x,y);
    }
    return table;
};
constexpr Table LUT = make_LUT();
constexpr Cell precomputedF(uint8_t x, uint8_t y) {
    return LUT[y][x];
}

http://coliru.stacked-crooked.com/a/0d406313f9bec451


如果你真的想坚持使用更接近原始代码的东西,你可以简单地使用来消除模板中的递归。它的最大深度为 2,而不是 2xtableSize。我还没有完全弄清楚创建最大深度为 1 的表的语法,但我怀疑这是可能的。std::make_integer_sequence<uint8_t,tableSize>()


template<uint8_t row, std::uint8_t... columns>
constexpr TableRow makeTableRow(std::integer_sequence<uint8_t,columns...>) {
  TableRow t = {{f(columns,row)...}};
  return t;
};
template<std::uint8_t tableSize, std::uint8_t... rows>
constexpr Table makeTable(std::integer_sequence<uint8_t,rows...>) {
  Table t = {{makeTableRow<rows>(std::make_integer_sequence<uint8_t,tableSize>())...}};
  return t;
};
constexpr Table lut = makeTable<tableSize>(std::make_integer_sequence<uint8_t,tableSize>());

http://coliru.stacked-crooked.com/a/345718b3818c2231

评论

2赞 Julien BERNARD 10/7/2023
谢谢!顺便说一句,对于任何找到这个答案的人,请确保你使用 C++20 来获取 constexpr std::p air。
0赞 Paul Sanders 10/7/2023
并使用 ,而不是constevalconstexpr