kchpchan
kchpchan

Reputation: 87

Pass by reference/value overload

Trying to figure out why no overloading-ambiguity caused in the following codes:

float foo2(float& i)
{
    cout << "call from reference" << endl;
    return i;
}
float foo2(float i)
{
    cout << "call from non reference"<<endl;
    return i;
}
int main()
{
    cout<<foo2(2); // print "call from non reference"
}

The foo2 whose parameters not passed by reference is called. Why? How to call the foo2 that pass reference parameters?

Upvotes: 7

Views: 2861

Answers (3)

Bert Bril
Bert Bril

Reputation: 66

Your question is in C++ terms, not in design terms. C++ supports things in a way because it makes sense in terms of design. C++ allows you to do a lot of things, but if you want to make good software with it you cannot stick to mere literal C++ rules, you need to go further. In practice that means you end up making your own rules.

In your case - well, I'd never make the reference variant if I did not actually change the variable in the function.

If you adopt such 'rules' for yourself, then you immediately see why the ref function doesn't bind: what is the point, in the first place, to change a loose constant?

If you make the right rules, you'll see that they are beautifully supported by C++. Like ... function changes an object: pass non-const ref. No change? const ref. Optional? const pointer. Take over mem management? non-const pointer.

Note that that is just the beginning, especially when multi-threading comes into play. You have to add things to the 'contract' of the function. Example for const ref: must the object stay 'alive' after the call? Can the object change during the call? And so forth.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726639

The foo2 whose parameters not passed by reference is called. Why?

Because you cannot pass a constant or any computed expression by reference to a function that takes a non-constant reference. To pass an expression by reference you need an assignable value - something that can appear on the left-hand side of an assignment expression. Since 2 cannot appear on the left side of an assignment expression, it cannot be used to call a function that expects a reference. When the reference is const, you can pass anything, because C++ will create a temporary variable, assign the expression to it, and pass a reference to function taking const reference.

How to call the foo2 that pass reference parameters?

There is no obvious way of doing that, because the moment you pass a variable or another expression that can become a reference, the compiler will complain that you are making an ambiguous call:

float f;
foo2(f); // <<== This will not compile

There is a way to call it, though: you can make a function pointer that matches only one of the two function signatures, and use it to make your call:

typedef float (*fptr_with_ref)(float&);

int main()
{
    cout<<foo2(2) << endl; // print "call from non reference"
    fptr_with_ref foo2ptr(foo2); // Only one overload matches
    float n = 10;
    cout<<foo2ptr(n) << endl; // Calls foo2(float&)
}

Demo.

Upvotes: 8

Emil Laine
Emil Laine

Reputation: 42838

The 2 you gave as a parameter for foo2 is an rvalue, which cannot be a reference. Thus the function accepting a reference cannot be called with it.

Upvotes: 4

Related Questions