I've been trying to find a way to skip a template parameter not located at the end of the template parameter list, in a derived class that has been assigned a default in its base class.
I've done some research on this topic, also here on SO. While similar questions have been discussed on SO - many answers basically suggesting it doesn't work were related to very special cases like the hash map case here. Also I found this answer by "Potatoswatter", which in my opinion contradicts the impossibility of skipping such a parameter. In his answer he claims this declaration would be valid:
template< class A, class B = int, class C >
class X;
Assuming it is true that a template parameter may not be skipped (unless at the end of the argument list) such a declaration would make no sense at all. Since B is assigned a default value, but followed by C which has no default, in this case value B would always have to be assigned explicitly, rendering the assignment of int as default for B completely useless. The only scenario where the declaration of X above would make sense is one where one of the following declarations of Y would be valid:
class Y : public X<double, , const std::string&> { ... }
class Y : public X<A = double, C = const std::string&> { ... }
So is it really impossible to skip a template parameter that is not located at the end of the template parameter list when deriving a specialized class?
If it is impossible why so, and why does legal syntax apparently suggest otherwise (see class X example above)?
If it is in fact not impossible, how can one skip a template argument that has been assigned a default?
The relevant standardese is contained in "Template Parameters [temp.param]" (14.1).
Essentially, a default argument may only be used if the parameter to which it applies is not followed by any non-pack parameters that do not have default arguments ([temp.param]/11). However, the syntax you quoted is usable in a declaration in the situation described by [temp.param]/10:
The word "class" is kind of hidden in your question, so I thought I'd mention (even though this isn't exactly an answer) that template parameters with defaults can be "skipped", sort of, in calls to function templates. Consider this code:
X
is deduced asdouble
(and the default, if any, would go unused).Y
cannot be deduced in this call, so the default ofint
is used.Z
is deduced asfloat
.Providing defaults for function template parameters happens a lot in the STL these days because of the undeduceability of
{}
in a function argument list. See for examplestd::exchange
or constructor #8 ofstd::optional
.You might expect that a similar trick could be used with constructor template argument deduction in C++17, but my experimentation suggests that this is not the case. In class template definitions, the compiler will produce a diagnostic if you put a template-parameter-with-default earlier in the list than a template-parameter-without-default.