11

In this question, I'll refer to my previous question.

In that question, I found that the following is not valid:

template<typename T, typename... A, typename S>
class C { };

This is because:

[It is not valid code] for class templates because their arguments must always be specified, which will always result in an ambiguity unless the parameter pack is at the end and slurps up any remaining template parameters.

That makes sense, of course and I got it.

Then, as an alternative approach, the following that involves a specialization has been proposed:

template<typename F, typename S>
class C;

template<typename T, typename... A, typename S>
class C<T(A...), S> { };

Actually, it seems to work, so thanks to the one that proposed it.

Anyway, what I don't understand is why this is valid code while the previous one was not.
Should it suffer from the same ambiguity of the previous solution? Why and how does the compiler solve that ambiguity in that case?
According with the previous question (see the link at the start of this question), it seems to me that still the variadic part should slurp up any parameters to the end, thus this code should not be valid as well.
I'm wrong, of course, but what's wrong exactly in my reasoning?

Community
  • 1
  • 1
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 2
    A partial specialization's template arguments are deduced, not explicitly specified. – T.C. Jan 23 '16 at 00:12

1 Answers1

7

In the class template, a prospective template argument list C<a,b,c,d,e,f> needs to match

template<typename T, typename... A, typename S>

in which ...A is just floating in a parameter list.

But in the specialization, what needs to be matched is not the list of template variabled but rather the pattern:

C<T(A...), S>

which is easy because the A... is delimited.

So in the template specialization, the list of parameters is just an inventory of symbols, some scalar and some parameter packs, which will appear in a pattern.

rici
  • 234,347
  • 28
  • 237
  • 341
  • But this doesn't really explain why the compiler can't match `T=a`, `A...= (b, c, d, e)` , `S=f` for the first case – Tristan Brindle Jan 23 '16 at 00:40
  • @TristanBrindle Because that's the way the standard specifies it. [\[temp.param\] §14.1 p11](http://eel.is/c++draft/temp.param#11): *If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter.* Exceptions are made for function templates __iff__ the template parameters following the pack *can be deduced*, and I imagine there is a similar exception somewhere else for partial specializations of class templates. – melak47 Jan 23 '16 at 01:45
  • 1
    @TristanBrindle: It's true, I didn't explain that. What I explained is that the second example is unambiguous. Note that the second example could have had two parameter packs: `template class C { };` and it would *still* be unambiguous, whereas the primary template `template` is even theoretically unambiguous. Maybe I'll rewrite the answer, though. – rici Jan 23 '16 at 04:41
  • I don't get it, sorry. I know that `A...` is delimited in `C`, but that `A...` comes from `template`, where it cannot be in such a position because it tends to be greedy. Moreover there is no way to deduce what's `S` and what's the length of `A` (like it would happen in a function with something like `void f(S s)`), so it seems to me that still it should not be valid code. What am I missing? – skypjack Jan 23 '16 at 08:13
  • Sorry, just woken up. You mean that the specialization is used as an example as `C c;`, so everything matches, `A...` is delimited and thus `S` can be deduced, so the specialization applies because it's full deducible. Got it, you are right!! Thank you. :-) – skypjack Jan 23 '16 at 08:17