【问题标题】:Why I cannot use previous argument values to define argument default values?为什么我不能使用以前的参数值来定义参数默认值?
【发布时间】:2015-08-16 22:05:49
【问题描述】:

例如,为什么我不能写这个:

void f(double x, double y = x);

声明一个函数f,其调用f(x)等价于f(x,x)

如果这对您来说似乎没有用,这里有一个可能的使用场景。在这个例子中,我声明f如下:

void f(double x, double y = expensiveComputation(x));

expensiveComputation 表示,您猜对了,这是一个计算速度非常慢的函数。我想给f 的用户传递y 的值的可能性,如果他以前计算过它,所以我不必在f 内再次计算它。现在,当然我也可以通过编写两个重载来解决这个问题:

void f(double x, double y);
void f(double x) { f(x, expensiveComputation(x)); }

但是随着参数数量的增加,编写重载变得令人厌烦。例如,试着写:

void f(double x, double p = expensiveComputation(x), 
                 double q = expensiveComputation2(x, p), 
                 double r = expensiveComputation3(x, p, q),
                 double s = expensiveComputation3(x, p, q, r));

使用重载。它只是更丑陋。默认参数是性感的。之前的参数不能用于定义参数默认值是否有更深层次的语法原因?

【问题讨论】:

  • 允许这种语法会强制实现从左到右评估参数?
  • @Brian 好点。为什么不强制实现从左到右评估参数?我忘了...
  • 在许多平台上,默认调用约定是将参数从最右边开始向左推入堆栈。 (然后被调用者从左到右弹出。)
  • @Brian 但是评估顺序和推送结果的顺序之间没有必然联系?
  • @Quentin 如果参数以不同的顺序进行评估和推送,调用代码会变得更加复杂。

标签: c++ default-arguments


【解决方案1】:

我不知道为什么默认参数不能这样,但也许你可以尝试将所有这些参数包装在一个结构(类)中?

struct ParamSet
{
    double x;
    double p;
    double q;

    ParamSet(double x)
        : x(x)
        , p(ExpensiveCompute1(x))
        , q(ExpensiveCompute2(x, p))
    {
    }
    ParamSet(double x, double p)
        : x(x)
        , p(p)
        , q(ExpensiveCompute2(x, p))
    {
    }
    ParamSet(double x, double p, double q)
        : x(x), p(p), q(q)
    {
    }

private:
    double ExpensiveCompute1(double x) {}
    double ExpensiveCompute2(double x, double p) {}
};      
void f(ParamSet ps);

仍然需要 ctor 重载,但没有比像您提供的那样编写 expensiveComputation() 系列更有效的方法了,并且至少所有东西都包含在结构中

另外,f()的签名可以修复,只有1个版本。

【讨论】:

    【解决方案2】:

    你可以使用可变参数模板来做类似的事情:

    template<typename... Args> void f(double x, Args... args)
    {
        typedef typename common_type<double, Args...>::type common;
        std::vector<common, sizeof...(args)> arguments = {{ args... }};
    
        if (arguments.size < 2) arguments.push_back(expensiveComputation(arguments[0]));
        if (arguments.size < 3) arguments.push_back(expensiveComputation2(arguments[0], arguments[1]));
        if (arguments.size < 4) arguments.push_back(expensiveComputation3(arguments[0], arguments[1], arguments[2]));
        if (arguments.size < 5) arguments.push_back(expensiveComputation4(arguments[0], arguments[1], arguments[2], arguments[3]));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-18
      • 1970-01-01
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 2021-12-27
      • 1970-01-01
      相关资源
      最近更新 更多