Error C1202 (stack overflow) when recursively computing a templated value or function when using a conditional operator

我的未来我决定 提交于 2019-12-02 10:12:41

问题


I am implementing functionality that provides the opportunity to translate the coordinates of the cells of the game board to the number of this cell.

This is what I'm trying (and failing) to make work.

#include <cstdint>
#include <utility>

using UInt32 = std::uint32_t;

template<UInt32... s>
using IndexSequence = std::integer_sequence<UInt32, s...>;

static constexpr UInt32 W = 8;
static constexpr UInt32 H = 8;

template<UInt32 x1, UInt32 x, UInt32 x2, UInt32 y1, UInt32 y2, UInt32... s>
static constexpr auto RegonImpl =
    (y1 <= y2) 
        ? (x <= x2)
            ? RegonImpl<x1, x + 1, x2, y1,     y2, s..., W * y1 + x>
            : RegonImpl<x1, x1,    x2, y1 + 1, y2, s...>
        : IndexSequence<s...>{};

template<UInt32 x1, UInt32 x2, UInt32 y1, UInt32 y2>
static constexpr auto Region = RegonImpl<x1, x1, x2, y1, y2>;

int main() {
    constexpr auto idx = Region<0, 0, 5, 5>();
}

Error C1202 (recursive type or function dependency context too complex) occurs when compiling.

Error output:

... Indexes<8,8>::Region<0,0,1,7>(void) noexcept' being compiled
... Indexes<8,8>::RegionImpl<0,0,0,1,7>' being compiled
... Indexes<8,8>::RegionImpl<1,0,0,1,7,0>' being compiled
... Indexes<8,8>::RegionImpl<2,0,0,1,7,0,1>' being compiled
... Indexes<8,8>::RegionImpl<3,0,0,1,7,0,1,2>' being compiled
... Indexes<8,8>::RegionImpl<4,0,0,1,7,0,1,2,3>' being compiled
... Indexes<8,8>::RegionImpl<5,0,0,1,7,0,1,2,3,4>' being compiled
... Indexes<8,8>::RegionImpl<6,0,0,1,7,0,1,2,3,4,5>' being compiled
... Indexes<8,8>::RegionImpl<7,0,0,1,7,0,1,2,3,4,5,6>' being compiled
... Indexes<8,8>::RegionImpl<8,0,0,1,7,0,1,2,3,4,5,6,7>' being compiled
... Indexes<8,8>::RegionImpl<9,0,0,1,7,0,1,2,3,4,5,6,7,8>' being compiled
...

As you can see the condition x <= x2 is always true, which should not be.

I tried to implement this functionality as follows:

template<UInt32... s, UInt32... t>
constexpr auto concat(IndexSequence<s...>, IndexSequence<t...>) noexcept {
    return IndexSequence<s..., t...>{};
}

template<UInt32 x, UInt32 x1, UInt32 y1, UInt32 x2, UInt32 y2>
static constexpr auto RegionImpl() noexcept {
    if constexpr (y1 <= y2) {
        if constexpr (x <= x2) {
            return concat(IndexSequence<W * y1 + x>{}, RegionImpl<x + 1, x1, y1, x2, y2>());
        } else {
            return RegionImpl<x1, x1, y1 + 1, x2, y2>();
        }
    } else {
        return IndexSequence<>{};
    }
}

template<UInt32 x1, UInt32 y1, UInt32 x2, UInt32 y2>
static constexpr auto Region() noexcept {
    return RegionImpl<x1, x1, y1, x2, y2>();
}

It works. But, if instead of the if statement to use the conditional operator (a ? b : c), then the same error occurs.

What actually happens here when using conditional operator?


回答1:


The ternary conditional in this case is not equivalent to if statement because it is a constexpr if statement.

With constexpr if statement,

If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated .

But with the ternary conditional, the templates are always instantiated. This leads to infinite recursion.

Note that if you replace the constexpr if with normal if you get the same error. See DEMO.



来源:https://stackoverflow.com/questions/54478729/error-c1202-stack-overflow-when-recursively-computing-a-templated-value-or-fun

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!