Search code examples
c++conditional-statementstemplate-meta-programming

C++: Conditionals in template meta programming


I am implementing a program generating the next prime number from a given number NUMBER known at compile time with C++ template metaprogramming. However, I am currently stuck because I need a conditional value in my template. So I am searching for something like a ternary operator equivalent in C++.

My current approach:

#include <iostream>

#ifndef NUMBER
#define NUMBER 6
#endif

template <int P, int K = P - 1>
struct is_prime
{
    enum { value = P % K != 0 && is_prime<P, K - 1>::value }; 
};

template <int P>
struct is_prime<P, 1>
{
    enum { value = 1 };
};

template<int P, bool B = is_prime<P>::value> 
struct next_prime
{
    // This doesn't work
    enum { value = ( B ? P : next_prime<P+1>::value )};
};

int main(int argc, char** argv)
{
    std::cout << "next prime >= " << NUMBER << ": " << next_prime<NUMBER>::value << std::endl;
    return 0;
}

When compiling with g++, this results in an error:

In instantiation of ‘struct is_prime<503, 4>’:
   recursively required from ‘struct is_prime<503, 501>’
   recursively required from ‘struct next_prime<3, true>’
   required from ‘struct next_prime<2>’
fatal error: template instantiation depth exceeds maximum of 1000 (use ‘-ftemplate-depth=’ to increase the maximum)

Is there a good way to do this without using C++ 11?


Solution

  • Usually I see this sort of problem solved through specialization

    template<int P, bool B = is_prime<P>::value> 
    struct next_prime
     { enum { value = next_prime<P+1>::value }; };
    
    template <int P> 
    struct next_prime<P, true>
     { enum { value = P }; };
    

    If you can use C++11 or newer, instead of defining a value, I suggest inheritance from std::integral_constant

    // std::bool_constant<boolValue> is available starting from C++17;
    // in C++11/C++14 you can use std::integral_constant<bool, boolValue>
    
    template <int P, int K = P - 1>
    struct is_prime
       : public std::bool_constant<P%K && (not is_prime<P, K-1>::value)>
     { };
    
    template<int P>
    struct is_prime<P, 2> : public std::bool_constant<P%2>
     { };
    
    template<int K>
    struct is_prime<2, K> : public std::true_type
     { };
    
    template<int P, bool B = is_prime<P>::value> 
    struct next_prime : public next_prime<P+1>
     { };
    
    template <int P> 
    struct next_prime<P, true> : public std::integral_constant<int, P>
     { };