转换具有多个参数的构造函数

Converting constructor with multiple arguments

本文关键字:参数 构造函数 转换      更新时间:2023-10-16

在 C++11 中,没有explicit关键字的构造函数可用于将参数列表隐式转换为其类。例如:

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};
^

我想知道为什么转换构造函数不会将列表{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

这是因为只有特定的地方允许在语言中使用大括号的初始化列表(基本上是逗号分隔的{}s之间的内容列表(。它可以放在=的右侧,因为规则说它可以。它可以用作函数调用表达式中的参数,因为规则说它可以。但它不能用于比较运算符的任何一方,因为规则不允许这样做。

我不知道这背后是否有根本原因,除了可能没有强烈的需求之外。

为了完成Barry的回答,我列出了所有可以出现brace-init-list的语句或表达式:

  • 函数调用:func({/*...*/},arg2)
  • 下标:obj[{/*...*/}];
  • 显式类型转换:type{/*...*/}
  • 新表达式:new type{/*...*/}
  • 分配
  • 和复合分配:a = {/*...*/}; b += {/*...*/};...
  • 在条件语句的条件下while (atype i={/*.../*})
  • 范围初始值设定项for(auto it:{/*...*/})
  • return 语句:return {/*.../*}(如果推导返回类型,则不返回(
  • 初始值设定项:atype a{/*...*}; atype b={/*.../*};或包括成员初始值设定项:a_memb{/*.../*}
  • 默认参数void f(atype a={/*.../*})

我想知道为什么转换构造函数不会将列表{1,2,3}转换为Date对象?

因为它不是"转换构造函数"。它只是"构造函数"。

列表初始化(使用大括号初始化列表时发生的情况(用于从值列表中初始化对象,正如人们可能从名称中期望的那样。x = {1, 2, 3};不是初始化对象。x是已初始化的对象。

因此,大括号初始化列表不能直接应用于现有对象;它们只能应用于正在初始化的对象。您要做的是使用该列表初始化Date然后将该Date复制到现有的x对象中。那是拼写x = Date{1, 2, 3};.

"转换构造函数"是执行隐式转换的构造函数。隐式转换从一种类型的对象转换为另一种类型的对象。列表初始化不是,也从来不是转换操作。Date x = {1, 2, 3};不会将列表转换为Date;它使用复制列表初始化规则使用列表初始化Date