1

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.

max66
  • 65,235
  • 10
  • 71
  • 111
  • I don't think you should be allowed to call a constructor though, so gcc should probably reject it as well. – vsoftco Jul 04 '16 at 13:20
  • @vsoftco - the idea is create a temporary object but... I think the problem is when this receive only an argument – max66 Jul 04 '16 at 13:22
  • Ohh I see, but I think the compiler believes you have a call there. I am not 100% sure though. In any case, constructor delegation should work just fine: `foo (const T0 & t0, const Ts & ... ts) : foo(ts...) {}` – vsoftco Jul 04 '16 at 13:24
  • @vsoftco - in some way, you're right: I've encountered this problem trying to solve a question of another person that was thinking, in this way, to call a delegate contructor; but I'm reasonably sure (`cout`ed `this` pointer) that `g++` create another object – max66 Jul 04 '16 at 13:29

1 Answers1

2

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • really interesting, but if you instantiate the template (calling `foo(1,2);`, by example), you get an error from `g++` too – max66 Jul 04 '16 at 16:16
  • @max66 it's a minimal demo. It will only work when you instantiate the template with a single argument. – n. m. could be an AI Jul 04 '16 at 16:20
  • I see, but I don't understand why g++ compile your templated function but don't compile `void bar (int i) { int(i); }` – max66 Jul 04 '16 at 16:48
  • In other words... what is `int(ts...)` according g++? If `sizeof...(ts) == 1U` should be like `int(i)` so "error: declaration of ‘int i’ shadows a parameter"; if `sizeof...(ts) > 1U` (say 2, for the following example) should be like `int(i, j)` so "error: expression list treated as compound expression in functional cast" – max66 Jul 04 '16 at 16:53
  • @max66 There is a syntactic ambiguity in the C++ **grammar** between "declaration" and "expression". If an ambiguous construct can be **parsed** as a "declaration", it is a "declaration". `int(ts...)` cannot be parsed such, because the C++ **grammar** does not have a production needed for such parse. Once the construct is classified as an expression, and not before that, you can start wondering what `sizeof...(ts)` would be, because if the construct is not classified as an expression, `sizeof...(ts)` has no meaning, because `ts...` has no meaning, as such syntax cannot be in a declaration. – n. m. could be an AI Jul 04 '16 at 17:16
  • Once you have established that `int(ts...);` is an expression statement and not a declaration, you can interpret it and instantiate relevant templates and expand parameter packs, and at this point it's a bit late to go back and clam that it was a declaration all along based on (not very well defined) similarity between the semantic value of `ts...` and something else. You could not possibly obtain that semantic value if it was a declaration. And is not even a syntactically correct declaration. You cannot obtain **any** semantic values from something that is not syntactically correct. – n. m. could be an AI Jul 04 '16 at 17:36
  • you convinced me; but I think that you last comments are an important component of the answer; could you add they in the body of the answer? – max66 Jul 05 '16 at 11:09
  • OK I'll try to add them. – n. m. could be an AI Jul 05 '16 at 11:17