Consider the following, minimal example (compiles without #1
and #2
):
void foo(void)
{ }
template<typename T> class Stage2;
template<typename Ret, typename... Args>
struct Stage2<Ret (Args...)>
{
template<Ret (*func)(Args...)>
static void foobar(void)
{ /* Do something */ }
};
template<typename FuncType>
struct Stage1
{
template<FuncType func>
static void bar(void)
{
Stage2<FuncType>::foobar<func>(); // #1, Not working
Stage2<decltype(func)>::foobar<func>(); // #2, Not working
Stage2<void()>::foobar<func>(); // #3, Working
}
};
int main(void)
{
Stage1<decltype(foo)>::bar<foo>();
return 0;
}
Why does it not compile with #1
and #2
, whereas it compiles just fine with #3
? In my opinion, #3
should be equivalent to the others as long as foo has the signature void()
, which it does in this example. Even the compiler tells me, that FuncType
is in fact void()
(see below).
Error message (the same for #1
and #2
):
main.cpp: In static member function ‘static void Stage1<FuncType>::bar()’:
main.cpp:21:40: error: expected primary-expression before ‘)’ token
Stage2<FuncType>::foobar<func>(); // #1, Not working
^
main.cpp: In instantiation of ‘static void Stage1<FuncType>::bar() [with FuncType func = foo; FuncType = void()]’:
main.cpp:29:37: required from here
main.cpp:21:33: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘void (*)()’ to binary ‘operator<’
Stage2<FuncType>::foobar<func>(); // #1, Not working
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
What am I missing here? I'm using g++ 7.2.0.
Note: I'm not really interested if this is useful in any way, I'd just like to know why it doesn't compile because it makes no sense to me.
Basically, what's going on is this:
Stage2<FuncType>::foobar<func>();
contains a dependent name (depending on FuncType), therefore you have to follow the correct C++-syntax for calling member templates (thus the syntax error messages), which is
Stage2<FuncType>::template foobar<func>();
Note that this does not apply for Stage2<void()>::foobar<func>();
as there is no dependent name involved.
The same applies to Stage2<decltype(func)>::foobar<func>();
, but this alone still won't fix it as there is some tricky obstacle. According to §14.1.8 [temp.param],
A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type “pointer to T” or “pointer to function returning T”, respectively.
decltype(func)
will be void(*)()
instead of void()
(even though FuncType
was specified to be void()
), so no function type but pointer to function type will be passed as template parameter to Stage2
for which there is no specialization provided (as Stage2<Ret (Args...)>
and Stage2<Ret (*)(Args...)>
are not the same), thus falling back to the default template declaration, finally yielding a "use of incomplete type" error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With