使用条件运算符递归计算模板值或函数时出现错误C1202(堆栈溢出) [英] Error C1202 (stack overflow) when recursively computing a templated value or function when using a conditional operator
问题描述
我正在实现一种功能,该功能提供了将游戏板单元格的坐标转换为该单元格编号的机会。
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.
这就是我
#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>();
}
编译时发生错误C1202(递归类型或函数依赖上下文太复杂)。
Error C1202 (recursive type or function dependency context too complex) occurs when compiling.
错误输出:
... 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
...
您可以看到条件 x< = x2
始终是真实的,但事实并非如此。
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>();
}
它有效。但是,如果不是使用 if语句
来使用条件运算符(a?b:c)
,则相同发生错误。
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
?
推荐答案
在这种情况下,三元条件不等同于 if
语句,因为它是 constexpr if
语句。
The ternary conditional in this case is not equivalent to if
statement because it is a constexpr if
statement.
使用 constexpr if
语句,
如果
constexpr if
语句出现在模板实体中,并且条件在实例化之后不依赖于值,因此在实例化封闭模板时也不会实例化废弃的语句。
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.
请注意,如果将 constexpr if
替换为普通的 if
您得到相同的错误。
请参见演示。
Note that if you replace the constexpr if
with normal if
you get the same error.
See DEMO.
这篇关于使用条件运算符递归计算模板值或函数时出现错误C1202(堆栈溢出)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!