Using auto as Template Parameter

Share the Article

The C++17 allows using auto as template parameter. The parameter shall become a non-type in this case. This means, the template parameter shall hold the actual value of specified template argument. Therefore, we cannot use such template parameter as datatype inside the body. The auto parameter is valid for both function as well as class templates. There are certain restriction on this feature, which we will discuss subsequently.

//N is a type template<typename N> class MainFunda { } //N has a value template<auto N> class MainFunda { }

Basic example with function template

Following simple example shows how to use auto template type with a function template. In each call, the N takes the value of different kind of data types at compile-time. Accordingly, the compiler instantiates the template with different types of values of N.

#include <iostream> //main header using namespace std;//for namespace template<auto N> void funda() { cout << N << endl; } int main() { funda<2>(); //N is int funda<'x'>(); //N is char funda<0xb>(); //N is hex int funda<true>(); //N is bool 1 funda<false>();//N is bool 0 funda<3l>(); //N is long int funda<6u>(); //N is unsigned int funda<-2>(); //N is signed int with -ve val return 0; }

Output

output of basic example using auto as template parameter

Constant L-values as arguments

Even the L-values which are constant at compile time are valid. Therefore, the code like, the following shall also work. However, if the “x” is not constant then compiler shall generate an error during compilation.

const int x = 5; funda<x>();

Invalid cases to instantiate a template using auto parameter

Certain data types do not qualify for a non-type template parameter. For instance, the auto parameter shall not accept a float or a double value. These are generally invalid values to become a template type. Probably, the additional complexity involved regarding how a machine may store the significant digits may cause such types to become unsuitable. Therefore, the following code shall generate an error.

#include <iostream> //main header using namespace std;//for namespace template<auto N> void funda() { cout << N << endl; } int main() { funda<5.2>(); //error return 0; }

Output

compiler error on using double to instantiate non-type template parameter

Another invalid case is of providing run-time addresses to instantiate such templates. A pointer having an address cannot instantiate the template with non-type parameter. This is because, the compiler cannot know the address of a variable before the program starts executing. Therefore, such address cannot be used in angular brackets.

The following code shall cause error.

#include <iostream> //main header using namespace std;//for namespace template<auto N> class MainFunda { public: MainFunda() { cout << N << endl; } }; int main() { int p; MainFunda<&p> m1; return 0; }

Output

compiler error on using address to instantiate non-type template parameter

Using Non-type as template parameter for class

The similar concept works with class template. Following example demonstrates this.

#include <iostream> //main header using namespace std;//for namespace template<auto N> class MainFunda { public: MainFunda() { cout << N << endl; } }; int main() { MainFunda<2> m1; MainFunda<'x'> m2; MainFunda<0xb> m3; MainFunda<true> m4; MainFunda<false>m5; MainFunda<3l> m6; MainFunda<6u> m7; MainFunda<-2> m8; return 0; }

Output

output of code using auto as template parameter with class template

Partial template specialization of template with non-type parameter

Just like the case of partial specialization with template types, similarly, there is concept with non-types. Basically, auto is a generic placeholder for any datatype. Therefore, in a partial specialization, specifying a particular type generates partially specialized templates. For Example, any particular type, like, a bool or an int, etc. for the same parameter name shall create partial specialization. Therefore, in such cases, the compiler instantiates partial version with data argument of this specific data-type.

#include <iostream> //main header using namespace std;//for namespace template<auto N> class MainFunda { public: MainFunda() { cout << N << endl; } }; template<bool N> class MainFunda<N> { public: MainFunda() { cout << "Boolean : " << N << endl; } }; int main() { MainFunda<2> m1; MainFunda<'x'> m2; MainFunda<0xb> m3; MainFunda<true> m4; //calls partial version MainFunda<false>m5; //calls partial version MainFunda<3l> m6; MainFunda<6u> m7; MainFunda<-2> m8; return 0; }

Output

output of code using auto template parameter and performing partial specialization

Full Template Specialization

To specialize the template class, we may specify exact value in place of template parameter. This is exactly similar as in case of template with typename paramtype. The following code, specializes same template on 2 integer values and one boolean value.

#include <iostream> //main header using namespace std;//for namespace template<auto N> class MainFunda { public: MainFunda() { cout << N << endl; } }; template<> class MainFunda<2> { public: MainFunda() { cout << "Number Two " << endl; } }; template<> class MainFunda<-2> { public: MainFunda() { cout << "Number Minus Two " << endl; } }; template<> class MainFunda<false> { public: MainFunda() { cout << "Boolean False " << endl; } }; int main() { MainFunda<2> m1; //calls specialization MainFunda<'x'> m2; MainFunda<0xb> m3; MainFunda<true> m4; MainFunda<false>m5; //calls specialization MainFunda<3l> m6; MainFunda<6u> m7; MainFunda<-2> m8; //calls specialization return 0; }

Output

output of code using auto template parameter and performing full specialization

Class Template Argument Deduction

Argument deduction is a new feature in C++17. In this feature, the compiler can automatically deduce parameter type from argument list during instantiation. Please read the page for full understanding. There is no need to explicitly specify the type in angular brackets. However, in case of non-type parameter, things work differently. The non-type parameter deduction happens in relation to a type and not independently.

The following example shows that the class has one typename and one non-type (auto) parameters. Once, the compiler deduces typename T using argument, the non-type also gets the value.

#include <iostream> //main header using namespace std;//for namespace template<typename T, auto N> class MainFunda { public: MainFunda(T (&x)[N]) { cout << x << ", size=" << N << endl; } }; int main() { MainFunda m1{"abc"}; MainFunda m2{"abcdef"}; MainFunda m3{"abcdef aldjfalj"}; return 0; }

Output

output of code using auto as template parameter with CTAD

In conclusion, the deduction shall not work if there is only non-type (auto) parameter. In the following example, the compiler cannot automatically, deduce the data-type with given argument (integer 2)

#include <iostream> //main header using namespace std;//for namespace template<auto N> class MainFunda { public: MainFunda(int x) { cout << "MainFunda(int)" << endl; } }; int main() { MainFunda m1{2}; return 0; }

Output

compiler error on failing class template argument deduction with non-type template parameter

Main Funda: The C++17 provides flexibility to use placeholder type “auto” as non-type parameter.

Related Topics:

Class Template Argument Deduction in C++17
What is a Tuple, a Pairs and a Tie in C++
C++ Multithreading: Understanding Threads
What is Copy Elision, RVO & NRVO?
Lambda in C++11
Lambda in C++17
Template type deduction in functions
How std::forward( ) works?
Rule of Three
How std::move() function works?
What is reference collapsing?
emplace_back vs push_back

Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *