【发布时间】:2015-03-18 01:19:52
【问题描述】:
最近我遇到了一个问题,不知何故(但只是不知何故)对我来说有意义。它基于将临时的构造解释为单个 (!) 构造函数参数的声明。请看下面的最小示例。
#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 的声明。这是有道理的,而且完全没问题,因为您可以使用 {} 括号来明确构造。但我不明白的是:
为什么bar0的构造有问题? 所有
Foos 都没有标准构造函数。因此,将Foo0(x)之类的内容解释为x的声明是没有意义的。为什么
bar1和bar2的构造有效? 对我来说很明显bar4的构造是有效的,因为我对所有临时的Foos 使用了{}-括号,因此我很明确我想要什么。-
如果只需要使用带有
李>Foos之一的{}-括号来解决问题......为什么bar3的构造会失败? 此外,在构造任何 Bar 之前声明 x。为什么编译器不抱怨呢?
最后一个问题与我的最后一行示例代码有关。长话短说:编译器认为我希望他做什么,我在哪里错过了阴影的出现?
PS:如果感兴趣的话——我使用的是 gcc-4.9.2。
PPS:我对bar 的构造函数进行了同样的尝试,将三个Foo0s 作为参数。同样的故事在这里。但是该错误没有说明冲突声明,而是重新定义x。
【问题讨论】:
-
你知道,
bar0是一个函数的声明,它接受三个Foos 并返回一个Foo,它本身不是一个Foo对象。此外,bar3的声明不起作用这一事实是您使用的任何编译器中的一个错误。该行应该像在clang 中一样工作。 -
@0x499602D2 在 g++ 4.8.1 中为我窃听
-
正确地说:
bar0是一个函数的声明,它接受三个Foos 并返回一个Bar。
标签: c++ temporary most-vexing-parse construction