我最近遇到了一个问题,对我来说有些困惑。这个问题基于将临时变量的构造解释为单个构造函数参数的声明。请看下面的最小示例。
#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.
}
I already read that expressions like:
Foo(a);
如果有标准构造函数,则会将解释为a的声明。这是有意义的,也是完全可以接受的,因为您可以使用{}括号使构建明确。但我不理解的是:
1. 为什么bar0的构建存在问题? 所有Foo都没有标准构造函数。因此,将类似于Foo0(x)的东西解释为对x的声明是没有意义的。
2. 为什么bar1和bar2的构建有效? 我认为bar4的构建是显而易见的,因为我对所有临时Foo使用{}括号,因此我明确说明了我想要的内容。
3. 如果只需要对其中一个Foo使用大括号以解决问题…为什么bar3的构建失败?
4. 此外,在构建任何Bar之前都声明了x。为什么编译器不会抱怨呢?
最后一个问题与我示例代码的最后一行有关。长话短说:编译器认为我想让他做什么,我在哪里遗漏了阴影的出现?
PS: 如果感兴趣--我使用gcc-4.9.2。 PPS: 我尝试使用bar的构造函数将三个Foo0作为参数。同样的故事。但错误并未提到冲突声明,而是关于重新定义x。
bar0
是一个接受三个Foo
并返回一个Foo
的函数声明,它本身不是一个Foo
对象。此外,bar3
的声明无法工作是由于您使用的编译器中存在错误。该行应该像在clang中一样工作。 - David Gbar0
是一个接受三个Foo
并返回一个Bar
的函数声明。 - sedriel