views:

158

answers:

6

I'm having a problem with optional function parameter in C++

What I'm trying to do is to write function with optional parameter which is passed by reference, so that I can use it in two ways (1) and (2), but on (2) I don't really care what is the value of mFoobar.

I've tried such a code:

void foo(double &bar, double &foobar = NULL)
{
   bar = 100;
   foobar = 150;
}

int main()
{
  double mBar(0),mFoobar(0);

  foo(mBar,mFoobar);              // (1)
  cout << mBar << mFoobar;

  mBar = 0;
  mFoobar = 0;

  foo(mBar);                     // (2)
  cout << mBar << mFoobar;

  return 0;
}

but it crashes at

void foo(double &bar, double &foobar = NULL)

with message :

error: default argument for 'double& foobar' has type 'int'

Is it possible to solve it without function overloading?

Thanks in advance for any suggestions.

Pawel

A: 

It is crashing because foobar is NULL. You are trying to assign a value to something that is NULL.

Marlon
The code never reaches the case where something is assigned to NULL because it does not compile before.
MKroehnert
+7  A: 

The default argument of a (mutable) reference must be an l-value. The best I can think of, without overloading, is

static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)
KennyTM
It may be worth defining lvalue for the asker. (Essentially, and informally, "something that can be assigned to.")
pkh
@pkh That definition is common, but wrong. Some rvalues can also be assigned to, for example `std::string("hello") = world`, and some lvalues cannot be assigned to, for example C-arrays and objects without an assignment operator. (Also, const lvalues cannot be assigned to, of course, but that seems to be well understood.)
FredOverflow
This can introduce subtle thread safety issues, if the dummy object is ever read.
Potatoswatter
+7  A: 

Why can't you use function overloading? Surely it's the easiest solution to your problem?

void foo(double &bar, double &foobar) 
{ 
   bar = 100; 
   foobar = 150; 
}

void foo(double &bar) 
{ 
   double foobar = 0.0;
   foo(bar, foobar);
}
In silico
I can but I just wanted to know if it is possible to solve the problem without overloading. Imagine waking up on an island where people really hate overloading :).
Moomin
@Moomin I would guess that the "I hate default parameters" island has much more inhabitants ;-)
FredOverflow
+7  A: 

Don't use references for optional parameters. There is no concept of reference NULL: a reference is always an alias to a particular object.

Perhaps look at Boost Optional. It's even specialized for reference types!

void foo(double &bar, optional<double &> foobar = optional<double &>())
Potatoswatter
+1, but I would prefer the full qualified names (always, but in particular when dealing with external libraries: `boost::optional`)
David Rodríguez - dribeas
A: 

You can do this crazy way:

void foo(double &bar, double &foobar = (*(new double())))

P.S. - I know its not pleasant but its the way. Also be sure not to leave memory leaks! :))

faya
Even if it didn't cause undefined behaviour, what would be a possible mechanism for safely deleting the optional parameter in the cases where it was actually used?
Charles Bailey
make it a smart_ptr and you're on!
Inverse
There is no way to avoid a leak - you can't tell inside the function whether the memory was allocated via the default argument or not, and there's no way outside the function to know the pointer. You're hosed (and leaking)!
Jonathan Leffler
+1  A: 

Another way to do this is to use pointers instead of references. This provides the semantics that you want without overloading. (Personally, I'd probably go with overloading.)

void foo(double* bar, double* foobar = 0)
{
   if (bar) *bar = 100;
   if (foobar) *foobar = 150;
}

   // ...

   foo(&mBar, &mFoobar);

   // ...

   foo(&mBar);

   // ...
pkh