If we have:
void foo(int) {}
void foo(const int&) {}
we cannot call foo
like this:
foo(3);
because the call is ambiguous:
error: call of overloaded 'foo(int)' is ambiguous 40 | foo(3); | ^ note: candidate: 'void foo(int)' 36 | void foo(int) {} | ^~~ note: candidate: 'void foo(const int&)' 37 | void foo(const int&) {} | ^~~
What we can do is explicitly provide the correct overload, for example via a function pointer:
auto (*ptr)(const int&) -> void = foo;
ptr(3); // calls the "const int&" overload, obviously
However, that kind of defeats the purpose of convenient overloads. The question is - can I somehow disambiguate the call in a more... elegant? way? Are there ever cases where it would be desired to provide both overloads, for T
and for const T&
?
When writing a C++ function which has args that are being passed to it, from my understanding const should always be used if you can guarantuee that the object will not be changed or a const pointer if the pointer won't be changed.
Yes, you should use const whenever possible. It makes a contract that your code will not change something. Remember, a non-const variable can be passed in to a function that accepts a const parameter. You can always add const, but not take it away (not without a const cast which is a really bad idea).
You can exploit templates. Overload resolution favours a non-template function over a template one, so converting one of the overloads to a template is a sufficent disambiguation:
#include <iostream>
void foo(int n)
{
std::cout << "By Value " << n;
}
template<int N = 0>
void foo(const int& n)
{
std::cout << "By Reference " << n;
}
int main() {
foo(1);
foo<>(1);
}
Granted, you need <>
to call the template one, but this could have some uses. Ostensibly more elegant than a function pointer? But alas it's not really much better than renaming say foo<>
to bar
.
It seems like you're asking whether we can force the overload resolution mechanism to select one signature over the other, rather than explicitly spelling out the signature that you want.
As far as I know, the only way to force overload resolution to pick the int
overload over the const int&
overload is to cast the argument to a volatile int
glvalue, and there is no way to force overload resolution to pick the const int&
overload over the int
overload.
In any case, I can't think of any reason why one would want to write this particular set of overloads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With