为什么我不能使用以前的参数值来定义参数默认值?

时间:2015-08-16 22:05:50

标签: c++ default-arguments

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

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

使用重载。这只是丑陋的。默认参数是性感的。是否存在更深层次的语法原因,为什么以前的参数不能用于定义参数默认值?

2 个答案:

答案 0 :(得分:1)

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

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个版本。

答案 1 :(得分:0)

您可以使用可变参数模板进行类似的操作:

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