C++ 转换具有多个参数的构造函数
在C++11中,不带显式关键字的构造函数可用于将参数列表隐式转换为其类。例如:C++ 转换具有多个参数的构造函数,c++,c++11,constructor,type-conversion,C++,C++11,Constructor,Type Conversion,在C++11中,不带显式关键字的构造函数可用于将参数列表隐式转换为其类。例如: class Date{ private: int d, m, y; public: Date(int _d, int _m=0, int _y=0) : m(_m), d(_d), y(_y) {} friend bool operator==(const Date &x, const Date &y) {return x.d==y.d;} }; int main() { Date
class Date{
private:
int d, m, y;
public:
Date(int _d, int _m=0, int _y=0) : m(_m), d(_d), y(_y) {}
friend bool operator==(const Date &x, const Date &y) {return x.d==y.d;}
};
int main()
{
Date x = {1,2,3}; // no error; using converting constructor
x == 1; // no error; converting constructor turns int into Date object
x == {1,2,3}; // error
}
对于x=={1,2,3}
,我得到了以下错误:
explicit.cc:16:10: error: expected primary-expression before ‘{’ token
x=={1,2,3};
^
我想知道为什么转换构造函数不将list
{1,2,3}
转换为Date
对象?特别是因为x==1
不会导致错误,为什么x=={1,2,3}
?您可能会特别惊讶于:
x = {1, 2, 3}; // ok
x == {1, 2, 3}; // error
operator==(x, {1, 2, 3}); // ok
这是因为在语言中,只允许在某些特定位置使用带括号的init列表(基本上是{}s
之间的逗号分隔的内容列表)。它可以放在=
的右边,因为规则说它可以。它可以用作函数调用表达式中的参数,因为规则说它可以。但是它不能在比较运算符的任何一侧使用,因为规则不允许它
我不知道这背后是否有一个根本原因,除此之外,可能没有强烈的需求
我想知道为什么转换构造函数不将list{1,2,3}
转换为Date
对象
因为它不是一个“转换构造函数”。它只是一个“构造器”
列表初始化(使用带括号的init List时发生的事情)用于从值列表初始化对象,正如人们从名称中所期望的那样<代码>x={1,2,3}代码>未初始化对象x
是一个已初始化的对象
因此,大括号的init列表不能直接应用于现有对象;它们只能应用于正在初始化的对象。您要做的是使用列表初始化日期
,然后将该日期
复制到现有的x
对象中。拼写为x=Date{1,2,3}代码>
“转换构造函数”是执行隐式转换的构造函数。隐式转换将一种类型的对象转换为另一种类型的对象。列表初始化不是,也从来不是转换操作<代码>日期x={1,2,3}
不会将列表转换为日期
;它使用复制列表初始化规则,用列表初始化日期。为了完成Barry的回答,我列出了可以出现大括号初始化列表的所有语句或表达式:
- 函数调用:
func({/*…*/},arg2)
- 订阅:
obj[{/*…*/}]
李>
- 显式类型转换:
type{/*…*/}
- 新表达式:
新类型{/*…*/}
- 赋值和复合赋值:
a={/*…*/};b+={/*…*/}代码>
- 在条件语句的条件下
while(atype i={/*…/*})
- 对于范围初始值设定项
for(auto-it:{/*…*/})
- return语句:
return{/*…/*}
(如果推导了返回类型,则不是)
- 初始值设定项:
a型{/*…*};atype b={/*…/*}代码>或包含成员初始值设定项:a_memb{/*…/*}
- 默认参数
void f(atypea={/*…/*})
我想补充一点,带括号的init列表不是表达式,因此它只能在允许表达式的有限上下文中使用。@Brian Until出于某种原因auto
推断它是一个初始值设定项\u list
。啊,C++的乐趣,有解析问题,特别是如果支持的init列表是左操作数。