3

I recently came across code that looked like this:

void function(int a, int b, int c){
  //...
}

int main(){
  //...
  (function)(1,2,3);
  //...
}

What is the point of wrapping the function name separately in parens?
Does it have any affect that would be different than function(1,2,3);?

Why does the language allow such syntax?

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
  • Did it make any difference to whatever output/return? – Khalil Khalaf Apr 02 '16 at 03:00
  • @FirstStep, I wasn’t in a position to run the actual code. What I have above is contrived, but I'm looking for any example where (func)(arg) would be different than func(arg). Something with scope? namespaces? lookup resolution? the function itself was NOT a macro. Maybe it was just a typo. – Trevor Hickey Apr 02 '16 at 03:04

2 Answers2

5

The only case I can think of where it would matter is when function is defined as a macro.

In C, standard library functions may also be implemented as function-like macros (for efficiency). Enclosing the function name in parentheses calls the actual function (since the function name is not followed by a ().

As for why the language allows the syntax, a function call consists of an expression of pointer-to-function type followed by the arguments in parentheses. In most cases, the prefix is a function name (which is implicitly converted to a pointer to the function), but it can be an arbitrary expression. Any expression may be enclosed in parentheses, usually without changing its meaning (other than affecting precedence). (But see Jonathan Leffler's comments for some counterexamples.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 3
    In "Effective Modern C++", Scott Meyers says: _“In `int x = 0;` `x` is the name of a variable, so `decltype(x)` is `int`. But wrapping the name `x` in parentheses—“`(x)`”—yields an expression more complicated than a name. Being a name, `x` is an lvalue, and C++ defines the expression `(x)` to be an lvalue, too. `decltype((x))` is therefore `int&`. Putting parentheses around a name can change the type that decltype reports for it! … C++14’s support for decltype(auto) […] means that a seemingly trivial change in the way you write a return statement can affect the deduced type for a function”_ – Jonathan Leffler Apr 02 '16 at 03:32
  • 4
    The book goes on to give two examples: `decltype(auto) f1() { int x = 0; … return x; // decltype(x) is int, so f1 returns int }` and `decltype(auto) f2() { int x = 0; … return (x); // decltype((x)) is int&, so f2 returns int& }` That's mostly just an FYI — but I found it very interesting, and unexpected. And it modifies slightly what you said in some unusual circumstances. – Jonathan Leffler Apr 02 '16 at 03:33
  • @JonathanLeffler: Weasel words added. – Keith Thompson Apr 02 '16 at 03:34
3

In addition to suppressing function-like macro expansions, wrapping an unqualified function name in parentheses suppresses argument-dependent lookup. For example:

namespace meow {
    struct kitty {};
    void purr(kitty) {}
}

int main() {
    meow::kitty stl;
    purr(stl); // OK, ADL finds meow::purr
    (purr)(stl); // error; no ADL is performed
}
T.C.
  • 133,968
  • 17
  • 288
  • 421