The following code
struct foo
{
foo ()
{ }
template <typename T0, typename ... Ts>
foo (const T0 & t0, const Ts & ... ts)
{ foo(ts...); }
};
int main()
{
foo f(1, 2);
return 0;
}
compile without problems with g++
(4.9.2) and give the following errors
tmp_002-11,14,gcc,clang.cpp:9:16: error: expected ')'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:13: note: to match this '('
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:9:14: error: redefinition of 'ts'
{ foo(ts...); }
^
tmp_002-11,14,gcc,clang.cpp:8:42: note: previous definition is here
foo (const T0 & t0, const Ts & ... ts)
^
2 errors generated.
with clang++
(3.5).
As usual my question is: who's right?
--- EDIT ---
Clarification: I know that foo(ts...)
can't be a call to a delegate constructor but (I think that can be) the construction of a temporary foo
object (another foo
object).
But, as pointed by vsoftco, what's happening when sizeof...(ts) == 1U
?
In that case, foo(ts...);
is a (re)declaration of a single variable ts
(so, I suppose, should be right clang++
) or the variadic syntax avoid this problem (so, I suppose, should be right g++
)?
There are C++11 standard experts that can clarify this?
p.s.: sorry for my bad English.
This looks like a clang bug. Here's a minimal reproduction:
template <typename ... Ts> void foo (Ts ... ts)
{
int(ts...);
}
(there's no even need to instantiate the template).
Judging from the error messages, clang interprets int(ts...);
as a declaration, which it cannot be, because (ts...)
cannot be a declarator.
One could ask: when ts... is a parameter pack of size one, shouldn't it be parsed similarly to ts
and thus cause the whole construct to be interpreted as a declaration? The answer is no.
There is a syntactic ambiguity in the C++ grammar between "declaration" and "expression-statement" productions. If an ambiguous construct can be parsed as a "declaration", it is a "declaration". int(ts...)
cannot be parsed such, because the grammar does not have productions needed for such parse. Once the construct is classified as an expression statement, and not before that, we can interpret ts...
as a parameter pack and calculate sizeof...(ts). If the construct is not classified as an expression, sizeof...(ts) has no meaning at all, because ts... has no meaning, as such syntax cannot be in a declaration.
Once it is established that int(ts...);
is an expression statement and not a declaration, one may interpret it and instantiate relevant templates and expand parameter packs. At this point it's too late to go back and claim that it was a declaration all along, based on the fact that sizeof...(ts) == 1
. One could not possibly deduce that sizeof...(ts) == 1
if it was a declaration (ts
wouldn't be a parameter pack then).
Moreover, clang seemingly insinuates that it is not even a syntactically correct declaration. One cannot possibly derive facts like sizeof...(ts) == 1
out of something that is not syntactically correct.