LI.*_*.LE 2 c++ arguments default-arguments
我使用以下代码得到“非静态成员引用必须相对于特定对象”,
class A{
int data;
int _default = 0;
public:
A(int data, int _default) : data(data), _default(_default) {}
void set(int data = _default){ this->data = data; }
};
int main(){
A a1(1, 1); a1.set(10); a1.set();
A a2(2, 2); a2.set(20);
}
Run Code Online (Sandbox Code Playgroud)
我想做的事?
A.set(),A::data设置为A::_defaultA.set(a),A::data设置为a非静态数据成员不能用作默认参数,它们应该从调用方上下文提供。
默认参数中不允许使用非静态类成员(即使它们没有被求值),
你可以提供另一个重载。
class A{
int data;
int _default = 0;
public:
A(int data, int _default) : data(data), _default(_default) {}
void set(int data){ this->data = data; }
void set(){ set(this->_default); }
};
Run Code Online (Sandbox Code Playgroud)
来自 2017 C++ 标准,第 11.3.6 节,第 9 段
非静态成员不应出现在默认参数中,除非它作为类成员访问表达式 (8.2.5) 的 id 表达式出现,或者除非它用于形成指向成员的指针 (8.3.1)。
所有其他 C++ 标准(之前和之后)都有类似的声明,尽管措辞和章节编号有所不同。上述“除非”两点均不适用于这种情况。
理论上可以(自 C++17 起)使用std::optional(来自 header <optional>)来避免过载,如下所示。
#include <optional>
class A
{
int data;
int _default = 0;
public:
// other members omitted
void set(std::optional<int> data = std::optional<int>())
{
this->data = data.has_value() ? data.value() : _default;
};
};
Run Code Online (Sandbox Code Playgroud)
或(如 Jarod42 在评论中所建议的)
void set(std::optional<int> data = std::nullopt)
{
this->data = data.value_or(_default);
};
Run Code Online (Sandbox Code Playgroud)
我在上面使用“名义上”这个词是因为,就我个人而言,我只会使用两个重载。对于普通人来说(可以说)更容易理解并使用所有 C++ 标准(不仅仅是因为 C++17)
void set(int data){ this->data = data; }
void set(){ set(this->_default); }
Run Code Online (Sandbox Code Playgroud)