在函数中使用非静态值作为默认参数

3

有没有一种优雅的方法可以在函数中使用非静态值作为默认参数? 我看到了一些早期针对相同问题的回复,最终总是要显式地编写重载。 在C++17中是否仍然需要这样做?

我想做的是类似于

class C {
  const int N; //Initialized in constructor

  void foo(int x = this->N){
    //do something
  }
}

不需要写

class C {
  const int N; //Initialized in constructor

  void foo(){
    foo(N);
  }

  void foo(int x){
    //do something
  }
}

这使得重载的目的不太明显。


1
好问题,表明在提问之前进行了研究。为什么不可能的原因在这里(https://dev59.com/um855IYBdhLWcg3wGQNM)。然而,我不知道与[C++17]标签有关的具体内容。 - gsamaras
@DeinFreund 我不知道,也许std::optional可以解决问题,但我会遵循Sam的建议进行重构。 - gsamaras
如果N是静态的呢? - Michael Chourdakis
@MichaelChourdakis 然后就是一个完全不同的问题了。 :) - gsamaras
如果N是静态的,那么可以使用N。这个问题可能也应该读作非静态成员,因为值不一定是静态的,只是不能是非静态成员的值。 - midor
显示剩余2条评论
1个回答

2

我认为比较优雅的一种方法是使用std::optional来接受参数,如果没有提供参数,则使用对象中的默认值:

最初的回答:

class C {
  const int N_; // Initialized in constructor
    public:
    C(int x) :N_(x) {}

  void foo(std::optional<int> x = std::nullopt) {
        std::cout << x.value_or(N_) << std::endl;
  }
};

int main() {
  C c(7);
  c.foo();
  c.foo(0);
}

您可以在标准的第11.3.6节中找到有关工作/不工作的完整说明。子节9描述了成员访问(摘录):

非静态成员不能出现在默认参数中,除非它出现为类成员访问表达式(8.5.1.5)的id-expression或者用于形成指向成员的指针(8.5.2.1)。[例如:在下面的示例中,X::mem1()的声明是不合法的,因为没有为非静态成员X::a提供对象作为初始化程序。

将"Original Answer"翻译成中文是"最初的回答"。
int b;
class X {
   int a;
   int mem1(int i = a);// error: non-static memberaused as default argument
   int mem2(int i = b);// OK; useX::b
   static int b;
};

1
这难道不是用运行时条件替换编译时差异,从而影响性能吗?我也不想在函数调用中添加一长串的 null。 - DeinFreund
它可能会,但通常可以通过编译器进行优化(https://godbolt.org/z/7HcJnQ)。老实说,我不确定您所说的空列表是什么意思,但显然存在一些权衡,如果您希望在编译时进行区分,则重载很可能是最好的选择。这也可以通过模板魔法完成:https://github.com/rmpowell77/LIAW_2017_param,但需要大量元编程,并且目前仍然不容易实现。 - midor
我会将 void foo(std::optional<int> x) 更改为 void foo(std::optional<int> x = std::nullopt) ,因为这样可以在没有可选参数的情况下进行调用。 - DeinFreund

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