具有多个参数的隐式转换以及运算符重载

pat*_*fox 1 c++ implicit-conversion c++11

我目前正在阅读"The C++ Programming Language"一书.以下是相关代码

class complex {
public:
  complex(double r, double i): re{r}, im{i} {}
  complex(double r): complex{r,0} {}
  complex(): complex{0,0} {}

  complex& operator-=(complex z) {
    this->re -= z.re;
    this->im -= z.im;
    return *this;
  } 
private:
  double re,im;
};

inline complex operator-(complex a, complex b) {
  return a -= b;
}

inline complex operator-(complex z) {
  return{ 0, 0 } - z;
}
Run Code Online (Sandbox Code Playgroud)

一元operator-给出错误 -

语法错误:缺少';' 在' - '之前

但是,编译器认为以下两种变体都是正确的

inline complex operator-(complex z) {
  return 0 - z;
}
Run Code Online (Sandbox Code Playgroud)

inline complex operator-(complex z) {
  return {-z.real(), -z.imag()};
}
Run Code Online (Sandbox Code Playgroud)

我认为在这两种情况下都会发生隐式转换.那为什么呢

inline complex operator-(complex z) {
  return {0,0} - z;
}
Run Code Online (Sandbox Code Playgroud)

标记为错误?

编辑 - 修复operator- =函数调用的返回类型,并添加operator-(),因为它与问题相关.

Pra*_*ian 5

我假设教科书中的示例也提供了二进制文件,operator-因为没有它,代码将无法编译,即使{0, 0}隐式转换为complex违规行上的代码.

return{ 0, 0 } - z;
Run Code Online (Sandbox Code Playgroud)

这行不能编译的原因是因为braced-init-list({0, 0})不是表达式,因此没有类型.所以它不能用作二进制的操作数之一operator-.

原因之所以return {-z.real(), -z.imag()};有效,是因为标准明确允许这样做.

§6.6.3/ 2 [stmt.return]

return语句的表达式braced-init-list称为其操作数....带有任何其他操作数的return语句只能用于返回类型不是cv 的函数void; return语句初始化要从操作数复制初始化(8.5)返回的对象或引用.

副本初始化在这种情况下副本列表初始化(§8.5.4[dcl.init.list] ),它会考虑的complex(double r, double i)构造,因为它不是explicit.


返回类型operator-=也很奇怪,它修改了complex实例,但随后返回了一个副本.典型的实现方式是

complex& operator-=(complex const& z) {
...
}
Run Code Online (Sandbox Code Playgroud)

  • @kaustubh braced-init在return语句中可以单独显示,在这种情况下它构造一个返回类型的临时,参见#8 [here](http://en.cppreference.com/w/cpp/language/list_initialization ). (3认同)