Jeffrey Cash
Jeffrey Cash

Reputation: 1073

Why can function call operator on temporary objects sometimes be interpreted as a declaration that does not shadow a parameter?

My question is similar to this answered question, but with one big difference.

If I try to compile the following,

void test(string x){
  int x = 5;
  cout << x << endl;
}

I get the expected warning:

In function ‘void test(std::__cxx11::string)’:
error: declaration of ‘int x’ shadows a parameter
    int x = 5;
        ^

Now to get to the meat of my question; if I have a type with a function call operator like the following:

struct foo{
  string bar;
  foo(const string& bar) : bar(bar) { }
  void operator()(){
    cout << "my bar is \"" << bar << '"' << endl;
  }
};

I can create a temporary object and call its () operator with foo("this will print")(); or with foo{"this will also print"}();

If I try to do the following, I will get a compiler error which is expected and can be explained with the post I linked above.

void redeclaration_error(){
  string x("lol");
  foo(x)();
}

However, things get weird here:

void hmm1(string str){
  foo(str)();
}
void hmm2(string str){
  foo{str}();
}

While hmm2 will print out its argument when called, hmm1 will do absolutely nothing. This is expected, as hmm1's body does nothing more than declare str to be of type foo. However, in the scope of hmm1, str is already declared as type string from the function's parameter, so why does this not result in a compiler error like error: declaration of ‘foo str‘ shadows a parameter?

I understand that the compiler is interpreting foo(str)(); as a declaration, and that lines like foo(str).operator()(); and (foo(str))(); will be interpreted as creating a temporary foo object and calling their function call operator, but why it it okay to declare a variable with the same name as a parameter in this circumstance?


Here's and Ideone link where I was playing around with this.

Upvotes: 3

Views: 117

Answers (1)

M.M
M.M

Reputation: 141554

A simpler program to produce the same issue (the extra parentheses are a red herring):

void f(int x)
{
    void x();
}

This is incorrect because of C++17 [basic.scope.block]/2:

[...] A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block.

If a compiler accepts this code then it is a compiler bug.

Upvotes: 1

Related Questions