手动设置重载函数的优先级

Manually prioritize overloaded functions

我对同一个函数有多个重载。对于某些参数集,几个重载同样适用,我自然会得到 "ambiguous overload" 错误。我想以某种方式为这些功能定义优先级,以便在出现歧义的情况下选择优先级最小的那个。

我尝试制作一系列模板助手 类、"tags"、P<0>P<1>、...,以便 P<N> 继承P<N+1> 有一些上限。因此,如果有两个函数 f(P<2>)f(P<4>),我调用 f(P<0>),第一个被选中。

它在实践中不起作用。经典的"clean"例子 "int/long" 和 "long/int" 函数仍然会产生歧义。我试图在函数中添加几个标签参数来增加标签的 "weight",但它没有帮助。

能否以某种方式调整此方法?

constexpr static int MAX = 20;

template<int N, class Enable = void>
class P {};

template<int N>
class P<N, typename std::enable_if<N < MAX, void>::type> : public P<N+1> {};

void f(int, long, P<2>) {}
void f(long, int, P<5>) {}

int main() {
    f(1, 2, P<0>());
}

首先,您可以简化标签类型构造,例如:

template <int N> struct P : P<N+1> { };
template <> struct P<MAX> { };

接下来,标签类型的自动扶梯仅在它们是您的超载的唯一决胜局时才起作用。也就是说,其他所有参数都是等价的——除了标签参数。您的调用仍然不明确的原因是您最终得到的转换序列是:

f(int, long, P<2>); // #1: Exact, Integral Conversion, P<0> -> ... -> P<2>
f(long, int, P<5>); // #2: Integral Conversion, Exact, P<0> -> ... -> P<2> -> ... -> P<5>

只有当 each 参数的转换序列至少与另一个重载参数的转换序列一样好时,一个重载才优于另一个重载。这不是真的:#1 在第一个参数中比 #2 更好,在第二个参数中更差。添加另一个参数不会改变该缺陷。

如果您在非不相交条件下使用 SFINAE,则标签类型有用:

template <class T, std::enable_if_t<cond_a<T>::value>* = nullptr>
void f(T&&, P<0> ) { ... }

template <class T, std::enable_if_t<cond_b<T>::value>* = nullptr>
void f(T&&, P<1> ) { ... }

template <class T, std::enable_if_t<cond_c<T>::value>* = nullptr>
void f(T&&, P<2> ) { ... }

f(whatever, P<0>{});

cond_acond_bcond_c 不需要不相交,并且每种情况下的第一个参数都相同。因此,对于 SFINAE 未删除的那些重载,最后的决胜局是标签。