10

Consider the following code:

template<typename F>
struct S;

template<typename Ret, typename... Args>
struct S<Ret(Args...)> { };

template<typename... Args>
using Alias = S<void(Args...)>;

int main() {
    S<void(int)> s;
    Alias<int> alias;
}

It works fine, as expected and both the line involving S and the one involving Alias define under the hood the same type S<void(int)>.

Now, consider the following changes:

int main() {
    S<void(void)> s;  // this line compiles
    Alias<void> alias;  // this line does not
}

I expected it to compile, for reasons that are similar to the ones above mentioned.
It goes without saying that it doesn't compile because of the line involving Alias, instead I get the error:

In substitution of 'template using Alias = S [with Args = {void}]'

[...]

error: invalid parameter type 'void'

The question is pretty simple: what I missed here?

skypjack
  • 49,335
  • 19
  • 95
  • 187

1 Answers1

5

From [dcl.fct], emphasis mine:

A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cv void.

In this case, Args... is a dependent type pack, so void is not allowed there. This idea is repeated in a note in [temp.deduct]:

[ Note: Type deduction may fail for the following reasons:
— [...]
— Attempting to create a function type in which a parameter has a type of void, or in which the return type is a function type or array type.
— [...]
—end note ]

Note that S<void(void)> compiles since void(void) is non-dependent and is equivalent to void(), so Ret(Args...) is never deduced to have void in the parameter list - it's deduced with Args... empty.


At least there's a simple workaround in that you can just write Alias<>.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • The workaround is obvious, but shouldn't it fail compiling both the lines for the same reason? Also `S` leads to a deduction that is attempting (well, succeeding) to *create a function type in which a parameter has a type of `void`*. Am I wrong? – skypjack Mar 08 '16 at 23:05
  • @skypjack Just found the section I was looking for. The `void` has to be non-dependent. – Barry Mar 08 '16 at 23:05
  • Thank you for the reference. Anyway, isn't also `Args` in `template struct S { };` a dependent type that should suffer from the same problem? – skypjack Mar 08 '16 at 23:19
  • @skypjack There I think you're fine since you're passing in `void(void)` explicitly. Not 100% sure, by any stretch – Barry Mar 08 '16 at 23:27
  • You know, I'm creating a new question for that, so start looking around for the right part of the reference!! :-) – skypjack Mar 09 '16 at 06:50
  • @skypjack Updated to clarify why `void(void)` works. – Barry Mar 09 '16 at 14:44
  • Thank you!! I've also opened a [question](http://stackoverflow.com/q/35885199/4987285) for that, if you want to participate it would be great. :-) – skypjack Mar 09 '16 at 15:55
  • Unfortunately I cannot use `Alias<>` in my real problem, because it's more complex that this one, but I'm creating a new question maybe for it. – skypjack Mar 10 '16 at 07:07