Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursion using template meta programming

Can somebody explain to me, why the first call using the template function is falling into an infinite loop, while the second compile-time function runs correctly?

#include <iostream> using namespace std;  template<int N, int M> struct commondivs {                                                 static const int val = (N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val; };  template<int N> struct commondivs<N,N> {   static const int val = N; };   int commondiv(int N, int M){     if(N==M){         return N;     }        return (N<M)?commondiv(N,(M-N)):commondiv((N-M),M);      }  int main() {      cout << commondivs<9,6>::val << endl;     cout << commondiv(9,6) << endl;     return 0; } 
like image 560
Exxul Avatar asked Nov 25 '19 15:11

Exxul


2 Answers

(N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val 

This line causes instantiation of both commondivs<N,(M-N)>::val and commondivs<(N-M),M>::val, even if the condition is known at compile time and one of the branches will never be taken.

Replace ? : with std::conditional_t, which doesn't have this limitation:

static const int val = std::conditional_t<N < M, commondivs<N,(M-N)>, commondivs<(N-M),M>>::val; 
like image 79
HolyBlackCat Avatar answered Sep 25 '22 09:09

HolyBlackCat


The problem is all the operands of conditional operator will be evaluated, so both commondivs<N,(M-N)> and commondivs<(N-M),M> get instantiated and their val get evaluated and then leads to recursive template instantiation.

You can apply constexpr if and put it in a constexpr static member function.

If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.

template<int N, int M> struct commondivs {                                                 constexpr static int get_val() {     if constexpr (N<M) return commondivs<N,(M-N)>::val; // if true, the else part won't be evaluated     else return commondivs<(N-M),M>::val;               // vice versa   }   static const int val = get_val(); }; 

LIVE

like image 32
songyuanyao Avatar answered Sep 23 '22 09:09

songyuanyao