92

For example a declaration such as that:

int (x) = 0;

Or even that:

int (((x))) = 0;

I stumbled upon this because in my code I happened to have a fragment similar to the following one:

struct B
{
};

struct C
{
  C (B *) {}
  void f () {};
};

int main()
{
  B *y;
  C (y);
}

Obviously I wanted to construct object C which then would do something useful in its destructor. However as it happens compiler treats C (y); as a declaration of variable y with type C and thus it prints an error about y redefinition. Interesting thing is that if I write it as C (y).f () or as something like C (static_cast<B*> (y)) it will compile as intended. The best modern workaround is to use {} in constructor call, of course.

So as I figured out after that, it's possible to declare variables like int (x) = 0; or even int (((x))) = 0; but I've never seen anyone actually using declarations like this. So I'm interested -what's the purpose of such possibility because for now I see that it only creates the case similar to the notorious "most vexing parse" and doesn't add anything useful?

4

2 Answers 2

89

Grouping.

As a particular example, consider that you can declare a variable of function type such as

int f(int);

Now, how would you declare a pointer to such a thing?

int *f(int);

Nope, doesn't work! This is interpreted as a function returning int*. You need to add in the parentheses to make it parse the right way:

int (*f)(int);

The same deal with arrays:

int *x[5];   // array of five int*
int (*x)[5]; // pointer to array of five int
8
  • 14
    And to complete the answer: disallowing the particular case that the asker is asking about would require an extra special-case rule. The current definition of how () work in a type is uniform throughout the type. Commented Apr 16, 2015 at 13:14
  • So the special-case applies to the most-vexing parse. This is because the syntax for initializing variables with constructor arguments was added later (in a hurry I guess?). Commented Apr 16, 2015 at 14:22
  • 1
    @FISOCPP Well. . yes. C++ came after C. . .
    – iheanyi
    Commented Apr 16, 2015 at 17:06
  • Does this answer equally apply to C, not just C++?
    – kdbanman
    Commented Apr 29, 2015 at 13:27
  • "variable of function type" what?!!
    – curiousguy
    Commented Oct 7, 2015 at 2:47
17

There's generally allowed to use parentheses in such declarations because the declaration, from the syntactical point of view looks always like this:

<front type> <specification>;

For example, in the following declaration:

int* p[2];

The "front type" is int (not int*) and the "specification" is * p[2].

The rule is that you can use any number of parentheses as needed in the "specification" part because they are sometimes inevitable to disambiguate. For example:

int* p[2]; // array of 2 pointers to int; same as int (*p[2]);
int (*p)[2]; // pointer to an array of 2 ints

The pointer to an array is a rare case, however the same situation you have with a pointer to function:

int (*func(int)); // declares a function returning int*
int (*func)(int); // declares a pointer to function returning int

This is the direct answer to your question. If your question is about the statement like C(y), then:

  • Put parentheses around the whole expression - (C(y)) and you'll get what you wanted
  • This statement does nothing but creating a temporary object, which ceases to living after this instruction ends (I hope this is what you intended to do).
4
  • 1
    As I mentioned, initially it was doing something in destructor, I guess it's pretty standard thing when you have some number of "chaining" functions for setting some parameters and then doing all the job in the destructor. Thanks for one more workaround though, I guess writing {} is the most valid one after all.
    – Predelnik
    Commented Apr 16, 2015 at 13:27
  • 4
    try to avoid making up your own grammar and use the one provided in the standard. <front-type> <specification> is misleading, and wrong. The grammar is <declaration-specifier> <declarator>
    – Steve Cox
    Commented Apr 16, 2015 at 17:07
  • You're right - I didn't look into the standard, just repeated the rule from my head. Actually in C++11 the role of <declaration-specifier> can be also played by auto keyword, so it's not even always a type.
    – Ethouris
    Commented Apr 17, 2015 at 11:11
  • @Pravasi Meet: If you have edited the part of my post and changed names in the given syntax schema, please change the names 3 lines below accordingly as well. Otherwise there are still old names "front type" and "specification" and therefore the post doesn't make any sense.
    – Ethouris
    Commented Jul 15, 2015 at 9:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.