3

A schematic of my problem...

class A
{
public:
    // etc.
protected:
    uint num;
};

class B : public A
{
public: 
    void foo(uint x = num); //bad
};

gives this error:

error: invalid use of non-static data member ‘A::num’
error: from this location

Why does this happen, and what can I do to work around this?

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
johndashen
  • 214
  • 1
  • 3
  • 11

3 Answers3

4

I suspect this happens (based on the complaint about non-staticness) because there is no this pointer for it to use to know which instance of B it should get num from.

The Microsoft compiler (at least) allows you to specify an expression, but not a non-static member. From MSDN:

The expressions used for default arguments are often constant expressions, but this is not a requirement. The expression can combine functions that are visible in the current scope, constant expressions, and global variables. The expression cannot contain local variables or non-static class-member variables.

Work-arounds for this are numerous and others have pointed out a few. Here's one more which you may or may not like:

void foo(uint* x = NULL) {
  uint y = (x == NULL ? num : *x);
  // use y...
}
i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • the workaround I used was assigning the default to UINT_MAX instead of NULL, but that caused conflicts elsewhere. i just overloaded foo() instead. thanks for the "this" explanation. – johndashen Jan 29 '10 at 02:54
  • @jeffamaphone: No suspicion needed, its simply illegal to refer to non-static members in default arguments (except for pointers to members and class member access expressions). – Georg Fritzsche Jan 29 '10 at 03:02
  • 1
    Not just Microsoft. The standard allows expressions, but it forbids non-static members in 8.3.6/9: "Similarly, a nonstatic member shall not be used in a default argument expression, even if it is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1)." – Rob Kennedy Jan 29 '10 at 03:09
  • Oh good. I didn't have time to go try to find the standard. :) – i_am_jorf Jan 29 '10 at 04:13
4

You can use overloading instead of default arguments.

class A
{
public:
    // etc.
protected:
    uint num;
};

class B : public A
{
public: 
    void foo(uint x);
    void foo() { foo( num ); }
};
outis
  • 75,655
  • 22
  • 151
  • 221
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
  • thanks... this is the obvious solution but for some reason it skipped my mind. (the //bad comment in the solution is no longer needed, it's just from my question code) – johndashen Jan 29 '10 at 02:51
1

you can create 2 foos

foo() //use num internally

foo(int x) //use x

Chris H
  • 6,433
  • 5
  • 33
  • 51