Question

Is it possible to deduce a non-type template parameter from a template function parameter?

Consider this simple template:

template <int N> constexpr int factorial()
{
        return N * factorial<N - 1>();
}

template <> constexpr int factorial<0>()
{
        return 1;
}

template <> constexpr int factorial<1>()
{
        return 1;
}

I would like to be able to change factorial so that I can alternatively call it like this:

factorial(5);

and let the compiler figure out the value of N at compile time. Is this possible? Maybe with some fancy C++11 addition?

Was it helpful?

Solution

Can't be done, unless you have a time machine.

The parameter to the function is handled at runtime. Yes, in your case it's a literal constant, but that's a special case.

In function definitions, the parameter types are fixed at compile-time (and thus, can be used to deduce template parameters), but parameter values are only fixed at runtime.

Why do you need this? Is it just so you don't have to type the <>'s?

OTHER TIPS

Your current code would normally be written as follows, I believe:

constexpr factorial (int n)
{
    return n > 0 ? n * factorial( n - 1 ) : 1;
}

If you call it with a constant-expression, such as factorial(5), then all the compiler magic will come into play. But if you do int a = 3; factorial(a), then I think it will fall back on a conventional function - i.e. it won't have built a lookup table of pre-computed answers.

In general, you should mark every function and constructor as constexpr if you can. You lose nothing, the compiler will treat it as a normal function if necessary.

I don't think you can do that; the only way you could do that would be having a constexpr function parameter that would be passed then as the template parameter for the template version of factorial, but constexpr function parameters are not admitted.

No, it is not possible, unless you want to create a huge switch statement :

int getFactorial( const int v )
{
  switch ( v )
  {
    case 1 : return factorial<1>();
    case 2 : return factorial<2>();
    //etc
    default:
       ;
  }
  return 0;
}

No, you can't do that. Template arguments can only be deduced from the type of function argument, not the value, which will not in general be known at compile time.

Of course, you could rewrite factorial as a non-template constexpr function; then it would be evaluated at compile time if the argument is known then.

Use an evil macro:

#define factorial(X) factorial<X>()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top