Closed atomgalaxy closed 4 years ago
From mpark: kill the sentence "It must bind exactly to a declared template-auto parameter".
From mpark: have an example of template template param that is not specified as such
from mpark: 5.1: template <typename class F, 8:56 should be template <template...
mpark: new kind of symbol, late checking, so the "eager checking" is really just where this symbol can be used, and late-check everything else.
consider exploring allowing using type = Arg; late
As for replacing class with typename it is actually a bit strange as in this context it must really be a class (counting a struct as a class).
I assume here you mean: template <template typename A> (typename|class) B
(that whole thing as a single template parameter declaration). I believe the rationale for allowing typename
here had to do with passing alias templates, which do not necessarily manifest as class types; that is, it's possible to pass non-class type templates as template template arguments.
Another interesting thing you can do is give names to the template parameters of template template parameters (the A
from my comment above). This is purely expository, but sometimes that exposition is helpful, in the same way that giving names to function parameters in forward declarations is helpful.
James, do you have some time to meet on whatsapp or something?
Typing stuff, give me a moment...
Shouldn't this be legal with "Down with typename!": https://godbolt.org/z/uFN97K ? Or is there language in the standard which would need to be changed? One of the main uses of template auto
is to apply transformations to argument packs, such as decaying all the types, so this should probably be a valid thing to do.
For reference, the relevant part of your example is:
template<typename... Ts>
struct Test
{
using type = B<A<Ts>::type...>;
};
Down with typename
! makes typename
optional in some places where a type is syntactically required. This example doesn't meet the requirements because template arguments are not syntactically required to be types, no matter what the template is. You have to know something about B
to make that determination.
That makes sense. I thought it might be something like that. I wonder if that behavior should be revisited for later checking in another paper to make the determination happen on usage. There are probably implications I'm not seeing, but the ability to say, pass through template auto
arguments through a filter struct would be really useful. It could be a narrow change, for instance only behavior relevant to the expansion of a parameter pack. Fixed numbers of parameters can use typename
without as much of a problem, but universal parameter packs have no way of expressing type/NTTP in their usage.
A lot of the use cases I have for template auto
involve parameter manipulation of mixed types and NTTPs, like decaying all types. One of the real uses cases I ran into where I needed universal templates was to generate combinations of template parameters for benchmarking.
template <typename T, size_t A, size_t B>
struct benchmark;
template <template <template auto...> typename T, template auto... Params>
struct enumerate_combinations;
using combinations = enumerate_combinations<benchmark,std::tuple<int,long>,std::integer_sequence<size_t,1,2>,3>::type;
// becomes std::tuple<benchmark<int,1,3>,benchmark<int,2,3>,benchmark<long,1,3>,benchmark<long,2,3>>
Currently, this can only be implemented with types, wrapping NTTPs in std::integral_constant, which is ugly and only works if the template doesn't have a pack to manually undo the wrapping and apply the arguments with the expected type/NTTP syntax for the parameter at each position.
At least some amount of late checking is required for all parameter transformation operation use cases. This could be made to be a deduction that only applies to the expansion of template auto...
parameter packs to keep the scope narrow.
New section on co/contravariance.