I'm learning C++ using the books listed here. In particular I read about variadic templates. Now, to further clear my concepts I'm also writing simple examples and trying to understand them by myself using debugger and cout statements.
One such program that compiles with gcc but is rejected by clang is given below. Demo.
template<typename T, typename... V>
struct C
{
T v(V()...);;
};
int main()
{
C<int> c; //works with gcc but rejected in clang
C<int, double, int, int> c2; //same here: works with gcc but rejected in clang
}
So my question is which compiler is right here(if any)?
Here is the error that clang gives:
<source>:6:12: error: '...' must be innermost component of anonymous pack declaration
T v(V()...);;
^~~
...
1 error generated.
Compiler returned: 1
This is a GCC bug. The correct syntax is T v(V...());, which Clang accepts and GCC rejects (incorrectly).
In a function parameter list, the ... that expands a pack must precede the parameter name, or be in the place where the name would otherwise be. This is more commonly seen in cases like V &&... v.
The related grammar is: function-definition -> declarator -> parameters-and-qualifiers -> ... -> parameter-declaration -> abstract-declarator ("abstract" = no parameter name).
[dcl.fct]/26 says that if there's an ambiguity in a function parameter list whether ... is a pack expansion or a C-style variadic parameter, it resolves to a pack expansion. But in this case there's no ambiguity, V()... leaves the pack unexpanded (which should be a compilation error) and ... should be a C-style variadic parameter.
GCC is wrong in accepting the program because a function parameter pack is introduced using an ellipsis (...) prior
to (or in the place of) the function parameter name.
This means in your example the correct way to declare the function with parameter of type pointer to function is T v(V...());. But note that gcc rejects this modified code. Demo
Here is the gcc bug report:
GCC accepts invalid program involving function declaration with pack expansion
It quite interesting to note that gcc rejects T v(V...()) but accepts T v(V...b()). Demo
template<typename T, typename... V>
struct C
{
//-------vvv---------->this is the correct way which gcc rejects
T v(V...());
//-------vvv---------->but gcc accepts this when we name the parameter
T v(V...b());
};
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