【问题标题】:member variable as default argument?成员变量作为默认参数?
【发布时间】:2021-07-13 05:36:33
【问题描述】:

我得到了“非静态成员引用必须相对于特定对象”的代码,

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);
}

我想做什么?

  • 当我们调用A.set()时,A::data被设置为A::_default
  • 当我们调用A.set(a)时,A::data被设置为a

【问题讨论】:

    标签: c++ arguments default-arguments


    【解决方案1】:

    非静态数据成员不能用作default arguments,它们应该由调用方上下文提供。

    默认参数中不允许使用非静态类成员(即使它们没有被评估),

    您可以提供另一个重载。

    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); }
    };
    

    【讨论】:

    • 在问这个问题之前,我删除了重载版本。实际上,我想要做的是删除重载。
    • @LI.LE 这是不可能的。除非将_default 设为static 成员,或者将其称为a1.set(a1._default);
    • @LI.LE 认为默认参数是二等公民。他们并不像人们期望的那样好。它们在呼叫站点被替换,即您不能使用私有成员作为默认值
    • “实际上,我想要做的是移除重载。” — 为什么?
    【解决方案2】:

    来自 2017 C++ 标准,第 11.3.6 节,第 9 段

    非静态成员不应出现在默认参数中,除非它作为 类成员访问表达式 (8.2.5) 的 id-expression 或除非它用于形成指向成员的指针 (8.3.1)。

    所有其他 C++ 标准(之前和之后)都有类似的声明,尽管措辞和章节编号有所不同。上述“除非”两点均不适用于这种情况。

    理论上可以(从 C++17 开始)使用 std::optional(来自标头 <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;
         };
     };
    

    或(如 Jarod42 在 cmets 中所建议的)

         void set(std::optional<int> data = std::nullopt)
         {
             this->data = data.value_or(_default);
         };
    

    我在上面使用“名义上”这个词,因为就我个人而言,我会简单地使用两个重载。对于普通人来说(可以说)更容易理解和使用所有 C++ 标准(不仅仅是从 C++17 开始)

     void set(int data){ this->data = data; }
     void set(){ set(this->_default); }       
    

    【讨论】:

    • std::nulloptoptional&lt;T&gt;::value_or 可能会有所帮助
    • 即。 void set(std::optional&lt;int&gt; arg = std::nullopt) { data = arg.value_or(_default); }.
    • @Jarod42 是的,这也是一个可行的选择。我会尽快编辑以说明这一点。
    【解决方案3】:

    你可以做的是你可以提供一个重载。

    void set(){ this->data = this->_default; }
    void set(int data){ this->data = data; }
    

    这将完成你想做的工作。

    【讨论】:

      猜你喜欢
      • 2020-11-27
      • 2021-12-29
      • 2021-07-05
      • 1970-01-01
      • 2015-09-15
      • 2015-01-15
      • 2017-02-17
      相关资源
      最近更新 更多