14

I was looking into most vexing parse, and I stumbled upon something like this:

Foo bar(Baz()); // bar is a function that takes a pointer to a function that returns a Baz and returns a Foo

This is quite different from the typical syntax of return-type(*name)(parameters). Are the parenthesis present the parenthesis for the parameter list, or are they for the name?

Krystian S
  • 1,586
  • 7
  • 23
  • 1
    Oh my C++, syntax can be confusing sometimes. If `Baz` were a _function_ of no parameters returning a `Foo`, then that declares `bar` as a variable of type `Foo` initialized to `Baz()`. But if `Baz` is a _type_ then `bar` is declared to be a function?! Crazy.... – Ray Toal Oct 01 '18 at 01:28
  • 2
    @RayToal sorry for the self-promotion, but you might like [this parsing abuse](https://stackoverflow.com/questions/47452953/print-macro-values-without-knowing-the-amount-of-macros/47453921#47453921) I put together last year ;) – Quentin Oct 01 '18 at 08:29
  • Self-promotion appreciated! – Ray Toal Oct 01 '18 at 22:44

3 Answers3

17

Fully explicit form:

Foo bar(Baz f());

bar is a function that takes a single parameter f, which is a function (taking no arguments) returning Baz.

Without naming the parameter:

Foo bar(Baz ());

The reason bar ends up taking a pointer to a function is that functions cannot be passed by value, so declaring a parameter as a function automatically decays it into a pointer. The above declaration is equivalent to:

Foo bar(Baz (*)());

// or:
Foo bar(Baz (*f)());  // with a named parameter

This is similar to void foo(int [10]) where int [10] also means int * in a parameter list.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • Should one syntax be used over another (disregarding the use of std::function)? If i were to have a function pointer as a parameter, should I write a normal function declaration and let it decay to a pointer, or should I just write out a function pointer declaration? – Krystian S Sep 30 '18 at 21:25
  • 3
    @KrystianS That's a matter of personal taste. I prefer being explicit, so when my parameters are pointers, I declare them as pointers (not as arrays or functions). – melpomene Sep 30 '18 at 21:28
  • You should define an alias beforehand and use that in the parameter list. For the sake of everyone's sanity. – Sebastian Redl Nov 25 '21 at 08:31
6

There are two sets of parentheses in the declaration. The outer set of parentheses are the parameter list of the function bar:

Foo bar(Baz());
       ^     ^

Baz() in this declaration is a function type. The parentheses in a function type declaration delimit the parameter list of that function.

Foo bar(Baz());
           ^^

To clarify: In the context of a function parameter declarator, a function type is adjusted to be a pointer to a function of that type. So the declaration is in fact equivalent to:

Foo bar(Baz(*)());
           ^ ^

The highlighted parentheses of this alternative pointer argument declarator are not present in the "pre-adjustement" declaration.

Relevant standard rule:

[dcl.fct]

The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. ...

eerorika
  • 232,697
  • 12
  • 197
  • 326
3

Are the parenthesis present the parenthesis for the parameter list, or are they for the name?

They are for the parameter list.

So:

Foo bar(Baz());

declares a function which accepts a single parameter of a type function which returns Baz and accepts no parameters.

This, in turns, equal to a a function declaration which accepts a single parameter of a type pointer to a function which returns Baz and accepts no parameters. as (from function):

The type of each function parameter in the parameter list is determined according to the following rules:

...

3) If the type is a function type F, it is replaced by the type "pointer to F"

...

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67