Ambiguous reference / value versions of functions

Consider the following function prototypes:

void Remove(SomeContainer& Vec, const std::size_t Index); SomeContainer Remove(SomeContainer Vec, const std::size_t Index); 

The second is implemented from the point of view of the first. That is, they are functionally identical in all respects, except that one is passed by reference, and the other is by value.

However, GCC says they are ambiguous in such cases, although the first form is the only one that does not return a value:

 Remove(SomeContainer, 123); 

Is there any workaround for this, or do I need to come up with different names for each form?

+4
source share
4 answers

The return type is not a reason for overloading functions.
Function overloading can be performed with only one of the following criteria:

  • No argument
  • Argument Type &
  • Sequence of arguments

The return type can be ignored by the caller and therefore is not an acceptable criterion for function overloading.

Having said the above, go over the value and passing the link will create ambiguity for the compiler. For instance,

 void doSomething(int i) { } void doSomething(int &i) { } int main() { int val = 10; doSomething(val); //Ambiguous } 

Here, the compiler cannot determine how to pass val to the doSomething() version. It can make a valid function call for any version, so it asks for help at compile time (since this is a static binding) and puts the calls as ambiguous.

In the case of, for example, you. It is a choice / preference to rename functions or pass a pointer argument that will make two functions overloaded (one name, but different types of arguments). However, it is important to take into account the requirement and the action that the function will perform when choosing a preference. Personally, I would not choose a pointer just for the sake of overloading. If I need to reinstall or indicate that my argument points to different variables, then it would be wise to select a pointer argument.

A simple way is to simply have two different function names. There is no overhead, and it is as efficient as any other function call.

+5
source

As already mentioned, the return type is not considered for overloading. However, the compiler does consider values ​​of equal values ​​and refers to different types, but usually does not know which version to call. In other words, having two overloaded functions that differ only in whether a parameter is pass by value or pass by reference is fine until you try to call it: potential ambiguity is not an error in C ++.

Example:

 void f(int) { cout << "value\n"; } void f(int&) { cout << "reference\n"; } int main() { int val = 42; f(val); // Error! Ambiguous. f(static_cast<int>(val)); // OK: The type is int. Will print "value" } 

I don’t know how to let you know that you want f(int&) , however, therefore there is not much practical use in this - I’m just trying to figure out how C ++ overloading works.

+3
source

You can help the compiler and users of your functions a bit by choosing more distinguished names:

 Container Removed( const Container& c, size_t index ); void Remove( Container& c, size_t index ); 

Adding const to an immutable version will also prevent users from accidentally invoking the imperative option (the compiler will not allow it, at least not for const containers).

+2
source

Passing by reference / value is not used to determine function overloading because it is not possible for the compiler to know what is required - both are equally good for the value passed as a parameter. And, as others point out, the return type is never considered.

+1
source

All Articles