Deduce non-type template parameter

template argument deduction
c template return type deduction
template argument for template type parameter must be a type
template argument list must match the parameter list
c check template type at compile-time
c++ template pointer parameter
c++ function as template parameter
template argument deduction/substitution failed

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?

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?

Deduce non-type template parameter, 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� Deduction from a function call. Template argument deduction attempts to determine template arguments (types for type template parameters Ti, templates for template template parameters TTi, and values for non-type template parameters Ii), which can be substituted into each parameter P to produce the type deduced A, which is the same as the type of the argument A, after adjustments listed below.

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.

Template argument deduction, Now you can also use it for deducing non-type template parameters. For example : template <auto value> void f() { } f<10>(); // deduces int. This is useful, as you� In order for a template to be instantiated, every template parameter (type, non-type, or template) must be replaced by a corresponding template argument. For class templates, the arguments are either explicitly provided, deduced from the initializer, (since C++17) or defaulted.

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.

Declaring non-type template parameters with auto, The desired effect is that the type of the corresponding non-type template argument be automatically deduced, much like similar syntax works� When the template arguments are deduced, there are two distinct types: The type of the template argument and the type of the parameter, they depend on the type of the argument. There are three cases for deduction, each behaving slightly differently, depending on how the parameter is declared.

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.

Declaring non-type template arguments with auto, This paper proposes allowing non-type template parameters to be declared with the auto template <auto v> struct S; // type of v is deduced� If you use a dependent name in a template declaration or template definition, the compiler has no idea, whether this name refers to a type, a non-type, or a template template parameter. In this case, the compiler assumes that the dependent name refers to a non-type, which may be wrong. This is the case in which you have to help the compiler.

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

Declaring non-type template parameters with auto, Template parameters can be types, non-types, and templates. the compiler can deduce the name at the point of the template definition. Templates (C++) 12/27/2019; 7 minutes to read +2; In this article. Templates are the basis for generic programming in C++. As a strongly-typed language, C++ requires all variables to have a specific type, either explicitly declared by the programmer or deduced by the compiler.

Types-, Non-Types, and Templates as Template Parameters , 2) A non-type template parameter with an optional name and a default value. templates, the arguments are explicitly provided, defaulted, or deduced from� Deduction for alias templates. When a function-style cast or declaration of a variable uses the name of an alias template A without an argument list as the type specifier, where A is defined as an alias of B<ArgList>, the scope of B is non-dependent, and B is either a class template or a similarly-defined alias template, deduction will proceed in the same way as for class templates, except

Template parameters and template arguments, 2) A non-type template parameter with an optional name and a default value templates, the arguments are explicitly provided, defaulted, or deduced from� A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.

13.10.2.5 Deducing template arguments from a type [temp.deduct.type], A type that is a specialization of a class template (e.g., A<int>) includes the types, templates, and non-type values referenced by the template argument list of the� Deducing non-type template arguments The compiler cannot deduce the value of a major array bound unless the bound refers to a reference or pointer type. Major array bounds are not part of function parameter types.

Comments
  • Why would you want to do that? The factorial function doesn't accept any parameters. What's the benefit of factorial(5) over the correct factorial<5>()?
  • @CodyGray: I think that the idea would be to create a generic factorial function able to calculate the result at compile time if it's given a compile-time-known expression, but also able to calculate it at runtime if the input is a normal variable.
  • @Matteo: So far as I understand, nothing is being calculated at runtime since the expression is declared constexpr. And anyway, I don't understand why there'd be any problem passing a "normal variable" instead of the 5 using the standard syntax. The question here is "how can I avoid typing angle brackets", and I don't understand the motivation.
  • I want to avoid having to change lots of code. Also, I find it to be more idiomatic, but that's something I can easily pass on ;)
  • @CodyGray: constexpr works just like @Matteo said: if all arguments in a constexpr function call are compile-time constants, the call will be evaluated at compile time, otherwise, it's executed at runtime like any other function.
  • Pretty much, I have a huge code base with calls to several functions which I rewrote as a template. Replacing the names is trivial, but turning all f(2, 3, "abc", true) into f<2, 3, true>("abc") is a little bit trickier.
  • How about a macro to convert f(2, 3, "abc", true) into f_impl<2, 3, true>("abc")?
  • I didn't know constexpr works opt-out like that. Sadly, the code is just an example and I need a fixed-size array inside the actual function, so I need a template with the array size as a parameter.
  • Perhaps build an array of function pointers to the templated functions at compile time, and look them up at runtime? factorial[3](.. other args ..)
  • @pezcode: change factorial to a macro that calls the template code, Aaron: youd be better of building an array of the results
  • @MooingDuck, yep, but see pezcode's comment on this answer - I think the real application is more complicated than this. I get the impression that some args are to be these templated-ints, whereas their may be other parameters also.
  • If you can mark every function and constructor as constexpr without any negative consequences, it (again) raises the question of why this isn't the default for C++11 compilers... I guess it's the sacred back-compat problem again.