Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternatives to using class attribute value as a method default parameter?

I want to achieve something like this:

class C
{
    int m_nVal;
public:
    C(int nVal) : m_nVal(nVal){}            

    void foo(int nVal = m_nVal)
    {
         // use nVal, if provided; otherwise use m_nVal
    }
};

C c(1);
c.foo();  // use 1
c.foo(2); // use 2

This is not possible as C++ standard says:

a non-static member shall not be used in a default argument

Options I have are:

(1) Overload foo():

class C
{
    int m_nVal;
public:
    C(int nVal) : m_nVal(nVal){}

    void foo()
    {
        // use m_nVal
    }

    void foo(int nVal)
    {
        // use nVal
    }
};

(2) Use static member:

class C
{
    static int m_nVal;
public:         
    void foo(int nVal = m_nVal)
    {
        // use nVal, if provided; otherwise use m_nVal
    }
};

I don't want to make m_nVal static member so option 1 seem the only one.

Are there any other ways to achieve this?

like image 550
Bojan Komazec Avatar asked Feb 21 '23 08:02

Bojan Komazec


2 Answers

There are other alternatives if you are willing to change the interface. You can use boost::optional:

// untested:
void foo( boost::optional<int> val = boost::optional<int>() ) {
    int value;
    if ( val ) value = *val;
    else value = m_val;
    // Now use `value` in the function
}

If you cannot use boost, you can write your own nullable wrapper. You just need to store the type (int) and a flag that determines whether it is set or not.

The next option is using a pointer to mark that the argument is optional:

void foo( int *pval = 0 ) {
    int value = (pval? *pval : m_val);
    // use value from here on
}

But the option with the pointer inhibits the use of rvalues as arguments to the function (i.e. you need a proper variable to call the function, you cannot do foo(1) but rather need to do int x = 1; foo( &x );, which is kind of a pain).

Finally you can use your approach of offering two overloads, one that takes the argument and one that doesn't and just forwards to the first:

void foo( int val ) {
   // actual implementation
}
void foo() {
   foo( m_val );
}

This might actually be the best option...

like image 74
David Rodríguez - dribeas Avatar answered May 08 '23 03:05

David Rodríguez - dribeas


The two options aren't equivalent. Making a member static shouldn't be a decision made on whether you want to use it as a default to a method or not.

If m_nVal is logically bound to the class, and not an instance, make it static.

If m_nVal is specific to each object of the class, don't, and use the first option.

like image 39
Luchian Grigore Avatar answered May 08 '23 04:05

Luchian Grigore