0

I'm creating a method and one parameter of that method asks for a reference of an unsigned int, but I want to put a default value on that parameter. For example:

#include <iostream>

using namespace std;

class A {
public:
    void sender();
private:
    unsigned int score = 10;
};

class B {
public:
    void receiver(unsigned int & score);
};

void A::sender() {
    cout << "Before: " << score << endl;
    B b;
    b.receiver(score);
    cout << "After: " << score << endl;
}

void B::receiver(unsigned int & score) {
    score = 100;
}

int main() {
    A a;
    a.sender();
    return 0;
}

Live demo: in here

The error happen when I do this:

void receiver(unsigned int & score = 10u);

And the compiler returns:

error: could not convert ‘10u’ from ‘unsigned int’ to ‘unsigned int&’

Live demo: in here

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
SH.0x90
  • 532
  • 2
  • 7
  • 19
  • 1
    you can't have default argument with reference type unless it is const reference – Bryan Chen Mar 04 '14 at 04:59
  • What do you want to happen? You're essentially trying to say `10 = 100`; why? – Potatoswatter Mar 04 '14 at 05:02
  • I want a default value because I can simply call the method without specify a score, and the default score will be '0', but this doesn't mean that I want to change as I do using a reference. - The reference there is just in case of I pass a variable as I did, but it's not exactly necessary. Understand? – SH.0x90 Mar 04 '14 at 05:04
  • @SH.0x90 No. Specifically, what do you want `10 = 100` to do? Is the computer just supposed to ignore that? – Potatoswatter Mar 04 '14 at 05:06
  • No, the example above is illustrating the usage of the variable as reference, but I want to pass also nothing, just call the method, and don't modify. - Let me try to explain this better: Imagine that I have a method, and that method has two parameters. The first one is necessary, and the second one is optional. - The second one when specified, I can use, and modify, but if it's not, I just know that, in default, I have the value '0'. But this doesn't mean that I will change the value as you are saying. The reference is only in case of passing a variable as reference. – SH.0x90 Mar 04 '14 at 05:09
  • 1
    If you want different functions that do different things, use overloading, not default arguments. – Potatoswatter Mar 04 '14 at 05:11
  • 1
    Please have a look at this answer: http://stackoverflow.com/a/1059656/3203158 – aroyc Mar 04 '14 at 05:13
  • 1
    I took the liberty of narrowing the scope implied by the title… type compatibility isn't the issue here. – Potatoswatter Mar 04 '14 at 05:19

3 Answers3

4

You cannot assign a literal1 to a non-const reference.

There are two scenarios where one will suit your situation:

You intend to modify the argument being passed to receiver()

If that is the case, the use a non-const reference (unsigned int & score) without the default parameter. In situations where you pass a literal or temporary object to it, then it will result in a compiler error.

a.receiver(10);  // Error

The above wouldn't make any much sense considering that you want to modify that argument (you wouldn't see the modification if C++ had allowed that2).

You intend to just use the parameter in a read-only fashion

Just use plain, non-reference, unsigned int, because const unsigned int& score is just a pain to write. In cases where you determine that an object is expensive to copy, then that is the time where you should have the parameter a const reference.

UPDATE: There are some cases where you want to modify something, but that something may or may not exist. In cases like that, you may want to use a non-owning pointer as the parameter.

   // Declaration
   void receiver(unsigned int* score = nullptr);

void B::receiver(unsigned int* score) {
    if(score) *score = 100;
}

...

a.receiver();    // Uses the default parameter

unsigned int x;
a.reciever(&x);

In this case, it only assigns to score when it points to some (assumed) valid variable. Pointers aren't that bad at all.

UPDATE 2: However, as @Potatoswatter have pointed out, you may be better off with function overloading.

void B::receiver() {
    // Do something else
}

void B::receiver(unsigned int& score) {
    score = 100;
}

You should use this in cases where you want your overloads to behave differently on different parameters.

However again, I prefer the first, non-default parameter option, rather than the pointer option and the overloading option, as it requires that the caller provide a parameter, which is much better when you are modifying something through a function.

UPDATE 3: You should also consider to have your function return the value instead of modifying it through a parameter. In cases where you don't need the current state of the object being modified, having a function return a value is much more intuitive. One caveat though is that the caller may forget to capture (assign) the return value, which could be dangerous if you are using that value as some resource ID to free something up.


1 And in general, a temporary object.

2 And the universe would probably blow up if 10 was magically transformed into 100 ;)

Community
  • 1
  • 1
Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
  • 1
    These are exactly my thoughts, but the entire question is how to add a default argument, and modifying the parameter is the *only* thing the function does. – Potatoswatter Mar 04 '14 at 05:09
  • I understand your thought and I respect, but read my comment above and try to understand what I want, if it's not possible, I will understand and continue that way that you wrote, my options. – SH.0x90 Mar 04 '14 at 05:11
  • 1
    @SH.0x90 See my update. That may possibly answer your question. – Mark Garcia Mar 04 '14 at 05:15
2

You want the argument type to be const unsigned int&. Otherwise, you can do something crazy, like try to assign 10 = 20, which doesn't make sense.

And that happens to be exactly that you did. The score = 100 line doesn't seem to be what you actually meant.

Scott Lawrence
  • 1,023
  • 6
  • 14
1

the value "10" isn't a reference- it's a value. By having a by-reference parameter, it must be called with a reference. Using a default parameter means you could call the function without specifying the parameter and the compiler would use the default.

Similarly, calling b.receiver(10); is not valid, but

int someInt = 10;
b.receiver(someInt);

is valid.

OSborn
  • 895
  • 4
  • 10