Recursion using template meta programming

(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;

The ternary operator is not like if constexpr: when a compiler sees it, it has to generate code for both branches. In other words, to instantiate a template commondivs<M, N>, a compiler instantiates both templates commondivs<N, M - N> and commondivs<N - M, M>.

In contrast to that, commondiv(N, M - N) and commondiv(N - M, M) are translated into two function calls. Which one is taken, will be decided when the function is actually called.

Addition.

HolyBlackCat gave a solution with std::conditional_t. Here is another one:

template<int N, int M>
struct commondivs {                                              
    static constexpr int min = (N < M) ? N : M;
    static constexpr int max = (N < M) ? M : N;
    static constexpr int val = commondivs<min, max - min>::val;
};

template<int N>
struct commondivs<N, N> {
    static constexpr int val = N;
};

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