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

use*_*490 12 c++ constructor type-conversion c++11

在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
}
Run Code Online (Sandbox Code Playgroud)

因为x == {1,2,3},我收到以下错误:

explicit.cc:16:10: error: expected primary-expression before ‘{’ token
       x=={1,2,3};
          ^
Run Code Online (Sandbox Code Playgroud)

我想知道为什么转换构造函数不会将列表转换{1,2,3}Date对象?特别是因为x == 1不会导致错误,为什么x == {1,2,3}呢?

Bar*_*rry 15

你可能会特别惊讶:

x = {1, 2, 3};            // ok
x == {1, 2, 3};           // error
operator==(x, {1, 2, 3}); // ok
Run Code Online (Sandbox Code Playgroud)

这是因为只有特定的地方允许使用braced-init-list(基本上是逗号分隔的东西之间的列表{}s).它可以在右侧,=因为规则说它可以.它可以用作函数调用表达式中的参数,因为规则说它可以.但它不能在比较运算符的任何一方使用,因为规则不允许它.

我不知道这背后是否有一个根本原因,可能不是强烈需要它.

  • 我想补充一点,*braced-init-list*不是*表达式*,因此它只能用于允许*expression*s的有限上下文集中. (5认同)

Oli*_*liv 5

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

  • 函数调用: 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={/*.../*})