Take the following minimal example:
using Type1 = std::function<void(void)>;
template <typename T>
using Type2 = std::function<void(T)>;
Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;
If the second type alias, I get the error "Argument may not have 'void' type". (I tested with Xcode 4.5, Clang/c++11/libc++, OS X 10.7.)
I find this curious: I would have expected Type1
and Type2<void>
to behave identically. What's going on here? And is there a way to rewrite the second type alias so I can write Type2<void>
and get std::function<void(void)>
instead of an error?
Edit I should probably add that the reason I want this is to allow for something like the following:
template <typename ... T>
using Continuation = std::function<void(T...)>;
auto someFunc = []() -> void {
printf("I'm returning void!\n");
};
Continuation<decltype(someFunc())> c;
Continuation<decltype(someFunc())>
becomes Continuation<void>
and I get the error.
Several answers already explain the rationale. To add to those answers, the specification says (C++11 §8.3.5[dcl.func]/4):
In your
Type2
example, theT
invoid(T)
is a dependent type--it depends on a template parameter.When a function is declared to take a parameter of type
void
, as instd::function<void(void)>
, that is really just a goofy way of saying that it takes zero parameters. But the way you've declared Type2 is as astd::function
with a signature that returns nothing (void), but that takes 1 parameter. void is not a type that can be used as a parameter, it is just a way of declaring that there are no parameters. So it doesn't work with Type2, because that requires an actual type that can be used as a parameter.Void can be interpreted as an empty parameter if you pass it to a function. You're not using a void pointer after all so
becomes
I don't have an actual answer, only what I said in the comment: You can't have
void
as a function type, as in:I believe that
T(void)
is only allowed as a compatibility notation for C (which distinguishes declarations and prototypes, very differently from C++, and which needs to be able to say "no arguments").So, the solution should be variadic:
That way you can properly have no arguments:
The short answer is "templates are not string substitution".
void f(void)
has meaning only so far as it is an alias forvoid f()
in C++, in order to be backwards compatible with C.The first step is to use variadics, as noted elsewhere.
The second step is figuring out how to map
void
returning functions to ... well, maybe something likestd::function<void()>
, or maybe something else. I say maybe something else because unlike the other cases, you cannot callstd::function<void()> foo; foo( []()->void {} );
-- it isn't a true continuation.Something like this maybe:
then use it like this:
which gives you the type you want. You could even add in an apply to continuation:
which lets you apply a continuation to an execution of a function uniformly if the incoming type is a void or if it is a non-void type.
However, I would ask "why would you want to do this"?