3

I have the following code, it compiles with gcc 4.4 with no warnings, and returns 42.

template<typename T>
struct foo
{ };

template<typename T>
struct foo<void (T)>
{
  enum { value = 42 };
};

int main()
{
  return foo<void ((int))>::value;
}

Now, I see why it should work when the template parameter is void (int), but what's the deal with the double parentheses? Is this legal in C++? Is it the same as void (int)?

Cheers

xcvii
  • 450
  • 3
  • 17
  • I'm obviously missing something... honk and another user feel it's necessary to point out that C++ is not Python - but why? This code seems perfectly un-Python-ish to me. –  Apr 21 '11 at 22:26
  • @delnan in Python the extra parentheses have a specific meaning, but in C++ they don't. A joke isn't funny anymore when it needs to be explained. – Mark Ransom Apr 21 '11 at 22:31
  • @Mark: A joke isn't funny either if it's based on misinformation. Don't you people know any Python? Now, `(expr,)` would be a singleton tuple, but `(expr)` is just `expr`. Simply wrapping something in parens doesn't change anything about it in Python, as in every sane language. –  Apr 21 '11 at 22:32
  • @Mark, @delnan, you are right, late afternoon brainfart. – Benjamin Bannier Apr 21 '11 at 22:38
  • If the second struct foo is a specialization, then shouldn't the template line be `template <>`? – Adrian McCarthy Apr 21 '11 at 22:45
  • @Adrian: it's a partial specialisation, for function types. It's still parametrised by the function's argument type. – Mike Seymour Apr 22 '11 at 01:53

4 Answers4

4

In this case, void ((int)) is identical to void (int).
void ((int)) part in foo<void ((int))> is called type-id.
According to §8.1/1, type-id is composed of type-specifier-seq and abstract-declarator.
In void ((int)), type-specifier-seq is void and abstract-declarator is ((int)), and abstract-declarator can be parenthesized arbitrarily.
This is legal in C and C++.

Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26
  • 2
    This is the answer. `void ((int))` is a funny *type-id* meaning the type `g` is declared to have in funny declaration `void (g(int))`, which has the same meaning as the more usual declaration `void g(int)`. – aschepler Apr 22 '11 at 00:42
3

The inner parentheses are used to change the order of evaluation of the expression. Order doesn't matter when there's only a single part to the expression, so they're effectively doing nothing.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    If this is legal, why does g++ reject `void f((int)) {}`? I suspect the original example is invalid syntax and the fact it's accepted is a compiler bug. – aschepler Apr 21 '11 at 22:43
  • That's true, but does it apply here? Redundant parens don't matter in an expression, but this is a type specification. – Adrian McCarthy Apr 21 '11 at 22:44
  • @Adrian, a type expression is an expression too. Parentheses don't matter in this case, but there are plenty of examples where they do. – Mark Ransom Apr 22 '11 at 00:15
  • @aschepler, I think your example is one of the cases I alluded to above. By telling the compiler to start the expression evaluation at the `int`, it no longer looks like a function specification. – Mark Ransom Apr 22 '11 at 00:16
  • 1
    Okay, but still, there are no expressions or evaluations involved here. – aschepler Apr 22 '11 at 00:43
1
  • Templates are unlike macros.

  • Your "void (T)" is same as "void T" and "void ((int))" is same as "void int" just like "void ((((int))))" is same as "void int". The expression in parentheses is evaluated as @Mark pointed out.

jbp
  • 1,581
  • 1
  • 10
  • 15
0

In this case, it's not needed for this purpose, but the main reason for double parens like this, is to avoid the most vexing parse.

The double parens aren't allowed in a function declaration, but are in a function call, so code that would otherwise produce the most vexing parse can be forced to be a function call by enclosing at least one argument in double parentheses.

Some of the code I included in a previous answer demonstrated this.

Community
  • 1
  • 1
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111