为什么有时可以将对临时对象的函数调用运算符解释为不包含参数的声明?

时间:2019-03-06 22:50:43

标签: c++ c++11

我的问题类似于this answered question,但有很大的不同。

如果我尝试编译以下内容,

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

我得到了预期的警告:

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

现在要解决我的问题;如果我的类型带有如下所示的函数调用运算符:

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

我可以创建一个临时对象,并使用()foo("this will print")();调用其foo{"this will also print"}();运算符

如果我尝试执行以下操作,将会收到预期的编译器错误,可以通过上面链接的帖子来解释。

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

但是,这里的事情很奇怪:

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

虽然hmm2在被调用时会打印出其参数,但是hmm1绝对不会做任何事情。这是可以预期的,因为hmm1的主体仅声明strfoo类型而已。但是,在hmm1的范围内,已经从函数的参数中将str声明为类型string,为什么为什么不导致类似error: declaration of ‘foo str‘ shadows a parameter的编译器错误? / p>

我了解编译器会将foo(str)();解释为声明,并且foo(str).operator()();(foo(str))();之类的行将被解释为创建临时foo对象并调用其函数调用运算符,但是为什么在这种情况下可以声明与参数同名的变量呢?


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

1 个答案:

答案 0 :(得分:1)

产生相同问题的更简单程序(多余的括号是红色鲱鱼):

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

由于C ++ 17 [basic.scope.block] / 2,这是不正确的:

  

[...]不得在函数的最外层块中重新声明参数名称   定义,也不在与 function-try-block相关的任何处理程序的最外面的块中。

如果编译器接受此代码,则它是编译器错误。