问题
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?
回答1:
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 set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are (8.3.6). [Example:
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
— end example]
回答2:
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:
template<class X, class Y = int, class Z>
void foo(X x, Y y, Z z) {
(void)x, (void)y, (void)z;
puts(__PRETTY_FUNCTION__);
}
int main()
{
foo(3.14, {}, 1.45f);
}
- Template parameter
X
is deduced asdouble
(and the default, if any, would go unused). - Template parameter
Y
cannot be deduced in this call, so the default ofint
is used. - Template parameter
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 example std::exchange or constructor #8 of std::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.
template<class X, class Y = int, class Z> // error!
struct Foo {};
来源:https://stackoverflow.com/questions/32414867/is-it-really-impossible-to-skip-template-parameters-with-default-arguments-in-c