I have a following function:
template<unsigned fromLine, unsigned toLine = fromLine>
void stateChanged()
{
// onStateChangeHandler[fromLine]();
if (fromLine < toLine)
stateChanged<fromLine + 1, toLine>();
}
which I call it in a following way:
stateChanged<0>();
stateChanged<1>();
stateChanged<2>();
stateChanged<3>();
stateChanged<4>();
stateChanged<5, 9>();
stateChanged<10, 15>();
I am receiving fatal error: template instantiation depth exceeds maximum of 900. I assumed in C++14 the if condition will stop it automatically. So, how to do this properly?
Using if constexpr instead of if will prevent this code from infinitely recurring.
As your code is written now, every instantiation of stateChanged requests a different instantiation of stateChanged.
before [Compiler Explorer]
after [Compiler Explorer]
template<unsigned fromLine, unsigned toLine = fromLine>
void stateChanged()
{
// onStateChangeHandler[fromLine]();
if constexpr(fromLine < toLine)
{
// If the above expression is false, this code is not compiled.
stateChanged<fromLine + 1, toLine>();
}
}
Update:
On C++14, the same effect can be produced with some SFINAE.
template<unsigned fromLine, unsigned toLine = fromLine,
typename std::enable_if_t< fromLine>=toLine >* = nullptr >
void stateChanged()
{
// onStateChangeHandler[fromLine]();
}
template<unsigned fromLine, unsigned toLine = fromLine,
typename std::enable_if_t< fromLine<toLine >* = nullptr >
void stateChanged()
{
// onStateChangeHandler[fromLine]();
stateChanged<fromLine + 1, toLine>();
}
C++14 after [Compiler Explorer]
Without the ability to use if constexpr in the template definition, you need to change how you do the looping in order to introduce a way for the compiler to reach a terminal state and stop the template instantiation.
We can do this with a helper class that, rather than going from start to finish, processes a number of lines.
template <unsigned curLine, unsigned numLines>
void updateStateChanged()
{
// onStateChangeHandler[curLine]();
stateChanged<curLine + 1, numLines - 1>();
}
template <unsigned curLine>
void updateStateChanged<curLine, 0>()
{
// onStateChangeHandler[curLine]();
}
// Then we can modify your original class to call this helper:
template<unsigned fromLine, unsigned toLine = fromLine>
void stateChanged()
{
updateStateChanged(fromLine, toLine - fromLine);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With