Search code examples
c++templatesgeneric-programming

Infinite loop while compiling template


Why does this course compiler to go to infinite loop. I'm using visual studio 2012 (Compiler VC++11).

template <unsigned N, unsigned To = N - 1>
struct is_prime
{
    static const bool value = (N % To != 0) && is_prime<N, To - 1>::value;
};

template <unsigned N>
struct is_prime<N, 1>
{
    static const bool value = true;
};

template <unsigned N>
struct is_prime<N, 0>
{
    static const bool value = false;
};

template <unsigned N>
struct next_prime
{
private:
    static const unsigned n_plus_one = N + 1;
public:
    static const unsigned value = is_prime<n_plus_one>::value ? n_plus_one : next_prime<n_plus_one>::value;
};

int main()
{
    cout << is_prime<5>::value << endl;   //Compiles. true.
    cout << is_prime<4>::value << endl;   //Compiles. false.
    cout << next_prime<4>::value << endl; //Infinite compiler loop.
    return 0;
}

And if I'll write the specialization of next_prime<100> without member value:

template <>
struct next_prime<100>
{

};

I'll see the compiler error. So, why is it even trying to compile it?


Solution

  • Because it evaluates next_prime<4>::value:

    template <unsigned N>
    struct next_prime {
    // ...
    static const unsigned n_plus_one = N + 1;
    // ...
    static const unsigned value = is_prime<n_plus_one>::value ? n_plus_one : next_prime<n_plus_one>::value;
    

    In the above next_prime<n_plus_one>::value must only be instantiated when is_prime<n_plus_one>::value is false.

    You can fix it with std::conditional<> which returns one of the types, depending on the condition:

    template <unsigned N>
    struct next_prime : std::conditional<
          is_prime<N + 1>::value
        , std::integral_constant<unsigned, N + 1> // not instantiated here
        , next_prime<N + 1>                       // not instantiated here
        >::type                                   // instantiated here
    {};