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

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

在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 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列表是左操作数。