C++在声明和定义中分割默认参数值

3
以下C++11代码是否有效?构造函数NoWay::NoWay的两个参数都有默认值,但一个在声明中指定,另一个在定义中指定。
#include <iostream>

class NoWay {
private:
  int foo;
  bool bar;

public:
  explicit NoWay(int foo, bool bar = true);
  bool isGood();
};

NoWay::NoWay(int foo = 4, bool bar) {
  this->foo = foo;
  this->bar = bar;
}

bool NoWay::isGood() { return (foo == 4) && (bar == true); }

int main(int argc, char **argv) {
  auto noway = NoWay();
  std::cout << noway.isGood() << std::endl;
}

这段内容在gcc下可以编译通过。
$ g++ --std=c++11 foo.cc

但是clang拒绝它。
$ clang++ --std=c++11  foo.cc
foo.cc:13:18: error: addition of default argument on redeclaration makes this constructor a default constructor
NoWay::NoWay(int foo = 4, bool bar) {
                 ^     ~
foo.cc:9:12: note: previous declaration is here
  explicit NoWay(int foo, bool bar = true);
           ^
1 error generated.
Exit 1

为什么不直接硬编码,然后这样写:this->foo = 4呢? - Omid CompSCI
1
你不能在必需参数之前设置可选参数,因为你只能省略参数列表末尾的参数。 - Barmar
@Barmar 的意图是两个参数都是可选的,但“可选性的语法表现”被分成声明和定义两部分。你是说定义甚至在语法上都不是良好的形式吗? - Greg Nisbet
2个回答

2
那个问题被称为核心问题1344:通过默认参数向类添加新的特殊成员函数。
根据c++14 standard,这在语法上是原则上有效的,新的默认值只是添加到已定义的值中。

8.3.6.6 除类模板的成员函数外,在类定义之外出现的成员函数定义中的默认参数将添加到类定义中成员函数声明提供的默认参数集中;

但如果

如果一个默认构造函数(12.1),复制或移动构造函数或复制或移动赋值运算符(12.8)被这样声明,则程序是非法的。

所以clang是正确的。 至少在C++14中是这样。

1
Clang在报告错误时是正确的。引用N4659,[dcl.fct.default],第6段:
“除了类模板的成员函数之外,在类定义之外出现的成员函数定义中的默认参数将添加到类定义中提供的默认参数集中;如果声明了默认构造函数(15.1),复制或移动构造函数或复制或移动赋值运算符(15.8),则程序是非法的。”
当(非模板)函数被定义(或重新声明)时,为其他参数声明默认值是有效的,只要您不为已有默认值的参数指定一个值,并且跨翻译单元不违反ODR即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接