Ambiguous : Prioritize overloading of f(A&) over f(A)

102 views Asked by At

How to prioritize (tell compiler) to use "a function receive reference" (#B) over "a function receive value" (#A)?

#include <iostream>
using namespace std;

class Heavy{/* ...... */}; //a complex class
Heavy generateHeavy(){
    return Heavy();
}
void f(Heavy x){   //#A I want LOW priority.
    std::cout<<"case 1: pass by value"<<std::endl;
}
void f(Heavy& x){  //#B I want HIGH priority.  (save CPU for big object)
    std::cout<<"case 2: pass by reference"<<std::endl;
}

int main() {
    //vvvv Here is existing code base that I don't want to touch.
    f(generateHeavy());   //compiler call case 1 -> ok (I prefer reference, though)
    Heavy heavy;
    f(heavy); //should call case 2, but compiler fail (ambiguous) <= question
    return 0;
}

This issue come from my first attempt to extend SFINAE to a real-world case that prefer passing by reference, if possible.

1

There are 1 answers

2
AudioBubble On BEST ANSWER

The way to literally do as you asked is

template <typename T = void>
std::enable_if_t<std::is_same<T, void>::value> f(Heavy x) { ... }

void f(Heavy& x) { ... }

The first is a function template, but only T = void is allowed. The second is not. All else being equal, non-templates are preferred over templates.


Now, in real code, you probably wouldn't do this. You'd look at which calls you wish to support, and find a more appropriate approach that fits those calls. @StoryTeller suggested &&:

void f(Heavy &&) { ... }
void f(Heavy &) { ... }

which means that when you've got an rvalue, such as your function result, the Heavy && overload will be called. That's usually fine, but note that it's not exactly the same as what you asked for:

const Heavy c;
f(c);

What you asked for would make this call f(Heavy). Instead, with the Heavy && overload, there is no overload that accepts this.

An additional overload void f(const Heavy &) could cover this. There's not enough information in the question to tell if this is an appropriate approach for your use case, but that's something that you should be able to figure out yourself.