Advantages of auto in template parameters in C++17
The template <auto>
feature (P0127R1) was accepted into C++ in the ISO C++ 2016 meeting in Oulu, Finland.
An auto
keyword in a template parameter can be used to indicate a non-type parameter the type of which is deduced at the point of instantiation. It helps to think of this as a more convenient way of writing:
template <typename Type, Type value>
For example,
template <typename Type, Type value> constexpr Type constant = value;
constexpr auto const IntConstant42 = constant<int, 42>;
can now be written as
template <auto value> constexpr auto constant = value;
constexpr auto const IntConstant42 = constant<42>;
where you don't need to explicitly spell out the type any more. P0127R1 also includes some simple but good examples where using template <auto>
with variadic template parameters is very handy, for example for implementations of compile-time lists constant values:
template <auto ... vs> struct HeterogenousValueList {};
using MyList1 = HeterogenousValueList<42, 'X', 13u>;
template <auto v0, decltype(v0) ... vs> struct HomogenousValueList {};
using MyList2 = HomogenousValueList<1, 2, 3>;
In pre-C++1z, while HomogenousValueList
could be simply written as
template <typename T, T ... vs> struct Cxx14HomogenousValueList {};
using MyList3 = Cxx14HomogenousValueList<int, 1, 2, 3>;
writing an equivalent of HeterogenousValueList
would not be possible without wrapping the values in some other templates, for example:
template <typename ... ValueTypes> struct Cxx14HeterogenousValueList {};
using MyList4 = Cxx14HeterogenousValueList<constant<int, 42>,
constant<char, 'X'> >;
Actually, the case of real values in mceo's (original) answer is explicitly not covered as non-type template parameter.
template <auto ... vs> struct HeterogenousValueList {};
using MyList1 = HeterogenousValueList<42, 'X', 1.3f>;
See the example given in the mentioned proposal: Modify §14.3.2 paragraph 2:
template<auto n> struct B { /* ... */ };
B<5> b1; // OK: template parameter type is int
B<'a'> b2; // OK: template parameter type is char
B<2.5> b3; // error: template parameter type cannot be double
Just stumbled over the same misconception myself a few days ago.
Here is another example (originally presented by @Rakete1111 as an answer for template template parameter of unknown type):
Extracting the value of SIZE without knowing its type:
template<std::size_t SIZE>
class Foo {};
template <template<auto> class T, auto K>
auto extractSize(const T<K>&) {
return K;
}
int main() {
Foo<6> f1;
Foo<13> f2;
std::cout << extractSize(f1) << std::endl;
std::cout << extractSize(f2) << std::endl;
}