函数调用中临时构造被解释为声明
Construction of temporary in function call is interpreted as declaration
最近我 运行 遇到了一个对我来说(但只是某种程度上)有意义的问题。它基于将临时构造解释为单个 (!) 构造函数参数的声明。请查看下面的最小示例。
#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的构建有问题?
所有 Foo
都没有标准构造函数。因此,将 Foo0(x)
之类的内容解释为 x
.
的声明是没有意义的
为什么bar1
和bar2
的构造有效?
对我来说很明显 bar4
的构造有效,因为我对所有临时 Foo
都使用 {} 括号,因此我很明确我想要什么。
如果只需要用{}括号和Foo
中的一个来解决问题...为什么bar3
的构造失败?
此外,x 是在构造任何 Bar 之前声明的。为什么编译器不抱怨?
最后一个问题与我最后一行示例代码有关。长话短说:编译器认为我希望他做什么,我在哪里错过了影子的外观运行?
PS: 如果有兴趣的话 -- 我用的是 gcc-4.9.2.
PPS:我对 bar
的构造函数进行了同样的尝试,将三个 Foo0
作为参数。同样的故事在这里。但是错误并没有说明冲突声明而是关于 x
.
的重新定义
1) Foo0(x) 在此实例中被视为函数 bar0 的参数。在这里,它是否具有标准构造函数并不重要。不是局部变量声明和初始化,只是函数声明中的参数声明。
2) 我猜这与解析有关,但如果我错了,请有人纠正我。示例 bar1 和 bar2 有效,因为编译器知道 bar1 和 bar2 是局部变量声明(并且不是函数声明)一旦它看到 {} 的第一次出现。这些首次出现的 {} 出现在 x 被声明为函数参数两次之前。
3) bar3的构造失败,因为编译器首先假定bar3是一个函数声明。函数声明采用三个参数,它们都命名为 x。显然,这是不正确的。
4) 函数声明中的 x 只是参数的名称。它与您之前声明的整数 x 在不同的范围内。
规则是,如果一个声明具有函数声明的语法,那么它就是一个;否则它是一个变量声明。这种令人惊讶的实例有时被称为 most-vexing-parse.
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
是return类型,参数类型是Foo0
,Foo1
和 Foo2
。参数名称都是 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
的对象 bar1
、bar2
和 bar4
。它们不能被解析为函数声明,因为 { }
表示法在函数声明中不是有效语法。
因此,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
;它没有任何方法。
最近我 运行 遇到了一个对我来说(但只是某种程度上)有意义的问题。它基于将临时构造解释为单个 (!) 构造函数参数的声明。请查看下面的最小示例。
#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的构建有问题? 所有
Foo
都没有标准构造函数。因此,将Foo0(x)
之类的内容解释为x
. 的声明是没有意义的
为什么
bar1
和bar2
的构造有效? 对我来说很明显bar4
的构造有效,因为我对所有临时Foo
都使用 {} 括号,因此我很明确我想要什么。如果只需要用{}括号和
Foo
中的一个来解决问题...为什么bar3
的构造失败?此外,x 是在构造任何 Bar 之前声明的。为什么编译器不抱怨?
最后一个问题与我最后一行示例代码有关。长话短说:编译器认为我希望他做什么,我在哪里错过了影子的外观运行?
PS: 如果有兴趣的话 -- 我用的是 gcc-4.9.2.
PPS:我对 bar
的构造函数进行了同样的尝试,将三个 Foo0
作为参数。同样的故事在这里。但是错误并没有说明冲突声明而是关于 x
.
1) Foo0(x) 在此实例中被视为函数 bar0 的参数。在这里,它是否具有标准构造函数并不重要。不是局部变量声明和初始化,只是函数声明中的参数声明。
2) 我猜这与解析有关,但如果我错了,请有人纠正我。示例 bar1 和 bar2 有效,因为编译器知道 bar1 和 bar2 是局部变量声明(并且不是函数声明)一旦它看到 {} 的第一次出现。这些首次出现的 {} 出现在 x 被声明为函数参数两次之前。
3) bar3的构造失败,因为编译器首先假定bar3是一个函数声明。函数声明采用三个参数,它们都命名为 x。显然,这是不正确的。
4) 函数声明中的 x 只是参数的名称。它与您之前声明的整数 x 在不同的范围内。
规则是,如果一个声明具有函数声明的语法,那么它就是一个;否则它是一个变量声明。这种令人惊讶的实例有时被称为 most-vexing-parse.
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
是return类型,参数类型是Foo0
,Foo1
和 Foo2
。参数名称都是 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
的对象 bar1
、bar2
和 bar4
。它们不能被解析为函数声明,因为 { }
表示法在函数声明中不是有效语法。
因此,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
;它没有任何方法。