Reputation: 56547
I am trying to understand what's going on in the following snippet:
// using FUN = void(*)(void);
using FUN = void(void);
template<FUN fun> struct Fun{};
int main ()
{
FUN fun;
Fun<fun>{};
}
I can use void(void)
as a function non-type parameter, everything is fine, the program compiles. However, changing the type to pointer to function, i.e. removing the comment in the first line and commenting the second line, results in the error
(g++) error: the value of 'fun' is not usable in a constant expression
(clang) error: non-type template argument of type 'FUN' (aka 'void (*)()') is not a constant expression
What exactly is going on? Isn't a function type actually the same as a pointer to function (i.e., implicitly convertible everywhere?) I understand that the pointer to function shouldn't work, since FUN fun;
in main
it's not a constant expression, but why does declaring FUN
as void(void);
make it work?
Upvotes: 0
Views: 290
Reputation: 119164
A non-type template-parameter of type “array of
T
” or “function returningT
” is adjusted to be of type “pointer toT
” or “pointer to function returningT
”, respectively.
([temp.param]/8 in C++14)
Therefore the template Fun
is the same template regardless of whether FUN
is declared to be a function or pointer to function type.
But, this block declaration:
FUN fun;
has a different meaning depending on what FUN
is. If FUN
is a function, this is a block declaration of a function (which, if odr-used, must be defined somewhere else). Generally, you can use the name of a function as an argument to a template parameter of type pointer to function---no issues here. But if FUN
is a function pointer, this creates an uninitialized function pointer. Since it's a non-const
object, it cannot be used as a template argument, just as an int
variable cannot be used as a template argument for an int
template parameter but a const int
variable can.
Upvotes: 3