views:

282

answers:

8

Is there a good method for writing C / C++ function headers with default parameters that are function calls?

I have some header with the function:

int foo(int x, int y = 0);

I am working in a large code base where many functions call this function and depend on this default value. This default value now needs to change to something dynamic and I am looking for a way to do:

int foo(int x, int y = bar());

Where bar() is some function that generates the default value based on some system parameters. Alternatively this function prototype would look like:

int foo(int x, int y = baz.bar());

Where baz is a function belonging to an object that has not been instantiated within the header file.

+6  A: 

Yes. What you've written works.

Lev
Really? I never would have thought.
Dima
Lol. I downvoted this as obviously wrong before trying it out myself.
Been programming C++ for 8 years and did not know this!
Justsalt
I keep discovering new things about C++ all the time :-)
Lev
+4  A: 

Go figure! It does work. Default arguments in C++ functions

Dima
+1  A: 

It should be perfectly valid to call a global function or reference a global object in this context, as long as the declaration of the function/object is in scope. It may or may not be advisable (in terms of good design), but it should work.

Charlie
+6  A: 

I would use two overloaded functions:

int foo(int x, int y);

int foo(int x){return foo(x,bar);}

If you allow the forwarding function to be inlined, then the performance penalty is likely to small to zero. If you keep the body of it out of line in a non-header file there may be a performance cost (likely to be small), but much more flexibility in implementation and reduced coupling.

Tim Sharrock
The suggestion on using overloaded functions is good, but the code in the questoin does work as-is.
Charlie
+5  A: 

What's wrong with simply removing the optional parameter in the first declaration and providing a single parameter overload?

int foo(int x)
{
    Bar bar = //whatever initialization
    return foo(x,bar.baz());
}

int foo(int x,int y)
{
  //whatever the implementation is right now
}

I think this tends to be much cleaner and more flexible than trying to use some dynamic default value.

A: 

Try making bar() a static member function. This will allow any part of the program which has such a static class in scope to access it. For example:

class Foo { public:

static int bar(); };

Then you would declare:

int foo(int x, int y = Foo::bar());

If you need different objects then pass in the instance of the object instead.

+2  A: 

Tangential, but that looks to me like it'd introduce dependence issues down the road. I'd go with stbuton.myopenid.com's approach.

Paul Nathan
+4  A: 

In the standard, section 8.3.6 (Default arguments), paragraph 5, they give an example using just this approach. Specifically, it calls out that default arguments are expressions, so a function call applies, albeit with restrictions such as name lookup and type compatibility.

In my workplace, we've used signatures like this:

void An_object::An_object(
  const Foo &a,
  const Bar &b,
  const Strategem &s = Default_strategem()
);

to allow clients to override a behavior in a class constructor. It came in handy for conditional behavior which affected performance of a translator...

Don Wakefield