不明确:优先考虑f(A&)超过f(A)的重载

时间:2017-01-01 08:41:32

标签: c++ sfinae ambiguous

如何确定优先级(告诉编译器)使用"函数接收参考" (#B)over"一个函数接收值" (#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;
}

这个问题来自我第一次尝试将SFINAE扩展到真实案例,如果可能的话,更喜欢通过引用传递。

1 个答案:

答案 0 :(得分:2)

按照你的要求实现的方式是

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

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

第一个是功能模板,但只允许T = void。第二个不是。在其他条件相同的情况下,非模板优先于模板。

现在,在实际代码中,您可能不会这样做。您将查看您希望支持的呼叫,并找到适合这些呼叫的更合适的方法。 @StoryTeller建议&&

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

这意味着当你有一个rvalue,比如函数结果时,将调用Heavy &&重载。这通常很好,但要注意它与你要求的不完全相同:

const Heavy c;
f(c);

您要求的内容是f(Heavy)。相反,在Heavy &&重载的情况下,没有任何重载可以接受它。

额外的重载void f(const Heavy &)可以涵盖这一点。问题中没有足够的信息来判断这是否适合您的用例,但这是您应该能够自己解决的问题。