Reputation: 20774
For example, why I cannot write this:
void f(double x, double y = x);
to declare a function f
, for which the call f(x)
is equivalent to f(x,x)
?
In case this doesn't seem useful to you, here's a possible usage scenario. In this example, I declare f
as follows:
void f(double x, double y = expensiveComputation(x));
where expensiveComputation
denotes, you guessed it, a function that does a very slow computation. I want to give the user of f
the possibility of passing in the value of y
if he has computed it previously, so I don't have to compute it again inside f
. Now, of course I can also resolve this by writing two overloads:
void f(double x, double y);
void f(double x) { f(x, expensiveComputation(x)); }
but writing overloads becomes tiresome as the number of arguments grows. For example, try to write:
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));
using overloads. It's just uglier. Default arguments are sexy. Is there a deeper syntactic reason why previous arguments can't be used to define argument default values?
Upvotes: 7
Views: 108
Reputation: 3035
I don't know why default argument can't go that way, but maybe you can try to wrap all those arguments in a 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);
Still need ctor overloads, but no more works than writing the expensiveComputation()
series like you provided, and at least all things are wrapped in the struct
Also, signature of f()
could be fixed, and there is only 1 version.
Upvotes: 1
Reputation: 905
You may use variadic templates for something similar:
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]));
}
Upvotes: 0