临时函数调用的构造被解释为声明



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

#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. 此外,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

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

因此,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;它没有任何方法。

1)

在这种情况下,Foo0(x) 被视为函数 bar0 的参数。在这里,它是否有标准构造函数并不重要。它不是局部变量声明和初始化,而只是函数声明中的参数声明。

2)我的猜测是这与解析有关,但是如果我错了,有人会纠正我。示例 bar1 和 bar2 有效,因为编译器一看到 {} 的第一次出现就知道 bar1 和 bar2 是局部变量声明(而不是函数声明)。这些 {} 的首次出现出现在 x 作为函数参数声明两次之前。

3) bar3 的构造失败,因为编译器首先假设 bar3 是一个函数声明。函数声明采用三个参数,这些参数都命名为 x。显然,这是不正确的。

4) 函数声明中的 x 只是参数的名称。它与您之前声明的整数 x 位于不同的范围内。

相关内容

  • 没有找到相关文章

最新更新