Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why compiler cannot decide which function to call without the reference operator?

Below you can see small function called max.

template <typename T>
T max(T& arg1, T& arg2) {    
    if (arg1 > arg2) {
        return arg1;
    } else {
        return arg2;
    }
}

When i call this function inside main, it perfectly works, but if i make remove reference from arguments

T max(T arg1, T arg2)  

Then compiler gives following error

main.cpp:18:21: error: call of overloaded 'max(int&, int&)' is ambiguous

It is clear that compiler could not decide whether to call my function or standard function. The question here how it can decide and work fine, when there is reference on the head of arguments ?

When i call the function with constant parameters

const int a = 12;
const int b = 24;
cout << max(a, b) << endl;

it calls the standard max function. But when i call with non const values, it calls my function.

I can understand that if the object is const, the the const function will be called elsewhere the non-const function will be called. But why it should be reference to trigger this mechanism ? Why it cannot decide without the reference operator is there ?

like image 951
Kürşat Kobya Avatar asked Jun 07 '26 19:06

Kürşat Kobya


2 Answers

This is a question about overload resolution, which nobody has yet addressed. Let's ignore templates for the moment, since they're not strictly relevant, and let's pretend we these overloads declared:

void foo(int& );       // (1)
void foo(const int&);  // (2)

What happens when we try to call foo with an lvalue?

int i;
foo(i);

Both candidates are viable. The first rule for determining which is the best viable candidate is conversion sequences, and [over.ics.rank]:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
— [...]
— S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.

S1 and S2 are both reference bindings, and the types to which the references refer (int and const int) are the same except for cv-qualifiers, but S2's referred type is more cv-qualified than S1's. The least-qualified reference wins. Hence, (1) is preferred.

This is exactly why your function template

template <typename T> T max(T&, T&); // (1)

is preferred to the standard function template:

template <typename T> T const& max(T const&, T const&); // (2)

The second part of the question introduces this additional overload:

void foo(int& );       // (1)
void foo(const int&);  // (2)
void foo(int );        // (3)

We know that (1) is better than (2), but there does not exist a rule differentiating between (1) and (3). There is no "reference is better than non-reference" or vice-versa rule. Thus, both candidates are equally viable - which is ill-formed. Hence the error about ambiguity. This is why:

template <typename T> T max(T, T); // (3)
template <Typename T> T const& max(T const&, T const&); // (2)

didn't compile for you.

like image 59
Barry Avatar answered Jun 09 '26 09:06

Barry


When you use

const int a = 12;
const int b = 24;
cout << max(a, b) << endl;

The compiler has no other option but to call for the standard max function as it is defined to receive constant references (I almost sure you have using namespace std; at the beginning of your CPP file).

When you call for max with non const parameters, the compiler has two options either to use your max or the std::max. In such case the compiler always picks the less restricting option, which is T max(T& arg1, T& arg2).

Since const on the input parameters is treated as part of the function signature

T max(T& arg1, T& arg2)

and

T max(const T& arg1, const T& arg2)

are not the same and it doesn't cause to ambiguity error, while

T max(T arg1, T arg2)

will cause the ambiguity error with the first case.

like image 41
Alex Lop. Avatar answered Jun 09 '26 07:06

Alex Lop.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!