c++ - 函数调用中临时构造被解释为声明

标签 c++ temporary most-vexing-parse construction

最近我遇到了一个问题,它以某种方式(但仅以某种方式)对我有意义。它基于将临时构造解释为单个 (!) 构造函数参数的声明。请查看下面的最小示例。

#include <iostream>

class Foo0{
public:
  Foo0(int a){};
  void doStuff() {std::cout<<"maap"<<std::endl;};
};

class Foo1{
public:
  Foo1(int a){};
  void doStuff() {std::cout<<"maap"<<std::endl;};
};

class Foo2{
public:
  Foo2(int a){};
  void doStuff() {std::cout<<"maap"<<std::endl;};
};

class Bar{
public:
  Bar(Foo0 foo0, Foo1 foo1, Foo2 foo2){};
};

int main () {
  int x = 1;

  Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’
  Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF
  Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF
  Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’
  Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me

  x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious though.
}

我已经读过这样的表达:

Foo(a);

被解释(如果有标准构造函数)作为 a 的声明。这是有道理的,而且完全没问题,因为您可以只使用 {} 括号使构造显式化。但我不明白的是:

  1. 为什么bar0的构建有问题? 所有 Foo 都没有标准的构造函数。因此,将 Foo0(x) 之类的内容解释为 x 的声明是没有意义的。

  2. 为什么bar1bar2 的构造有效? 对我来说很明显 bar4 的构造有效,因为我对所有临时 Foo 使用了 {} 括号,因此我明确了我想要什么。

  3. 如果只需要用{}括号和Foo中的一个来解决问题...为什么bar3 失败?

  4. 此外,在构造任何 Bar 之前声明 x。为什么编译器不提示?

最后一个问题与我最后一行示例代码有关。长话短说:编译器认为我想让他做什么,我在哪里错过了阴影的出现?

PS:如果有兴趣——我使用的是 gcc-4.9.2。
PPS:我对 bar 的构造函数进行了同样的尝试,将三个 Foo0 作为参数。同样的故事在这里。但该错误并未说明声明冲突,而是说明了 x 的重新定义。

最佳答案

规则是,如果声明具有函数声明的语法,那么它就是一个;否则它是一个变量声明。这种令人惊讶的实例有时被称为 .

Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’

这是一个函数声明:bar0是名字,Bar是返回类型,参数类型是Foo0Foo1Foo2。参数名称都是 x 这是非法的 - 函数参数的名称必须不同。如果将 x x x 更改为 x y z 错误消失了)。

Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF
Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF
Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me

这些行并创建Bar 类型的对象bar1bar2bar4。它们不能被解析为函数声明,因为 { } 符号在函数声明中不是有效语法。

因此,Foo0{x} 等是为Bar 的构造函数提供参数的表达式。 Foo0{x}Foo0(x) 是用初始化器 x 声明类型为 Foo0 的临时对象的等效方法.

Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’

我认为这是一个编译器错误; Foo2{x} 部分表示该行不能是函数声明;它看起来像是变量 bar3 的有效声明。

x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious

x 是一个 int ;它没有任何方法。

关于c++ - 函数调用中临时构造被解释为声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28034742/

相关文章:

c++ - 从存储在 std::container 中的结构中提取元素

c++ - 从套接字转换(解析)谷歌 Protocol Buffer 流

c++ - 为什么部分初始化一个类然后调用委托(delegate) ctor 失败?

string - 我如何制作格式!从条件表达式返回 &str?

c++ - 从元组中解包参数

c++ - 对由类型运算符创建的临时引用

c++ - 为什么我需要 std::get_temporary_buffer?

c++ - 为什么 std::function 在这种情况下不起作用?

c++ - 使用匿名对象时,默认构造函数和复制构造函数都不会被调用

c++ - 最令人烦恼的解析是否带有合格的 id?