Advantages of Auto in Template Parameters in C++17

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

auto' as a template argument placeholder for a function parameter

This syntax is valid in the C++ Concepts Technical Specification, but not in C++20. In C++20 concepts, auto is only permitted at the top level in a function parameter type. The relevant rule is [dcl.spec.auto] paragraph 2:

A placeholder-type-specifier of the form type-constraint[opt] auto can be used as a decl-specifier of the decl-specifier-seq of a parameter-declaration of a function declaration or lambda-expression and, if it is not the auto type-specifier introducing a trailing-return-type (see below), is a generic parameter type placeholder of the function declaration or lambda-expression. [Note: Having a generic parameter type placeholder signifies that the function is an abbreviated function template (9.3.3.5 [dcl.fct]) or the lambda is a generic lambda (7.5.5 [expr.prim.lambda]). —end note]

(If you check the wording in the most recent working draft at the time of writing, you will find a somewhat different rule. The above rule was modified by core issue 2447, which was voted into the C++20 final draft at the Prague committee meeting a week ago.)

The decl-specifiers in a function parameter are the initial sequence of keywords and type names at the start of the parameter declaration. The above rule allows auto there at the top level:

void f(auto x);

... but only as a decl-specifier. auto is not permitted when nested within a decl-specifier:

void f(std::vector<auto> x);

... and is also not permitted elsewhere in the parameter type:

void f(void (*p)(auto));

Use of auto in template parameters: Some usage examples and... how to make it work with constant size C arrays?

As far I know, you can't so simply.

As you can read in this page

Array and function types may be written in a template declaration, but they are automatically replaced by pointer to object and pointer to function as appropriate.

So you can write

template <auto a, typename TVal>
inline void fill_all(const TVal &v)
{ }

// ...

static int a[4] {};

fill_all<a>(2);

but fill_all() see the type of a as a int *, not as int[4].

So you can use it as pointer but you have lost the information about the dimension.

The best I can imagine is call a constexpr function that return the size of the array and put this value as template parameter (or function argument)

template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
{ return N; }

template <auto a, std::size_t N, typename TVal>
inline void fill_all (TVal const & v)
{ std::fill(a, a + N, v); }

// ...

static int a[4] {};

fill_all<a, getDim(a)>(2);

but, unfortunately, I don't see a way to avoid the explicit call of getDim() in the explicit template argument list.

Combining auto template parameters with std::optional, possible?

You could deduce what type of std::optional you want from the function passed in.

Then you can return an empty optional if it throws.

#include <iostream>
#include <optional>

template <auto Func, typename E, typename ...Args>
auto safeCaller(Args&& ...args)
{
using ret = std::optional<decltype(Func(std::forward<Args>(args)...))>;
// this could even be wrapped in a loop for retrying
try
{
return ret{Func(std::forward<Args>(args)...)};
}
catch (E &e)
{
// ... perform some logging perhaps? or whatever else is relevant
return ret{};
}
}

int foo(std::string bar)
{
return bar.size();
}

int main()
{
// specialise safeCaller to work on foo and to expect std::runtime_error
auto result = safeCaller<foo, std::runtime_error>("baz");
if (result)
{
std::cout << *result << std::endl;
}
return 0;
}

Is There a Workaround for Visual Studio's Lack of Support for auto Template Parameters?

auto non-type template parameters were introduced only in VS 2017 version 15.7.0.

Templates that are designed to take any type as a non-type parameter can now use the auto keyword in the template parameter list. This allows instantiations to use any type instead of needing to determine and supply the type of template parameter at the point of instantiation.

Before that version they are not supported.

c++ auto for type and nontype templates

Are there plans for such an extension in the next c++20 release?

No.

Is there some fundamental problem in having a syntax like template<auto... X>, with X any type or nontype template parameter?

It would be a totally new concept in the language - having a name refer to either a type or a value in the same place. So it'd come with all sorts of additional questions - and probably additional language features to check if X is a type or not.

The syntax likely cannot be template <auto... X> struct Y { }; since that syntax already has meaning and means a bunch of values and Y<int>{} is ill-formed.

There are definitely places where such a thing would be useful though. A proposal would just have to address these issues.

How to enable auto nontype template parameter pack for same type of parameters

You can make use of the decltype construct as shown below:

template<auto T1, decltype(T1)... Args> struct Custom
{
};

Working Demo



Related Topics



Leave a reply



Submit