对重载函数模板的模糊调用 - 即使一个更专业化?

Bar*_*rry 10 c++ templates overloading c++11

考虑以下:

#include <utility>

template <int N>
using size_ = std::integral_constant<int, N>; 

template <int From>
void f(size_<From>, size_<From+1> ) // (1)
{ }

template <int From, int To>   // (2)
void f(size_<From>, size_<To> )
{ }

int main()
{
    f(size_<0>{}, size_<1>{});
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang都认为这个电话含糊不清.为什么?是不是(1)更专业(2)

注意:我知道这可以通过额外enable_if_t<(To > From+1)>投入轻松修复(2),但我不会想到我需要这样做.

Col*_*mbo 3

不出所料,CWG 问题中的一个类似示例(即#455)解决了这个问题:

如果其中一个参数是非推导的,则部分排序应仅考虑专业化中的类型:

template<typename T> struct B { typedef T type; };

template<typename T> char* f3(T, T);                   // #7
template<typename T> long* f3(T, typename B<T>::type); // #8

char* p3 = f3(p3, p3); // #9
Run Code Online (Sandbox Code Playgroud)

根据我的推理,#9 应该产生歧义,因为第二对是 (T, long*)。第二种类型(即 long*)取自#8 的专业化候选者。EDG 和 GCC 接受了该代码。VC 和 BCC 发现了歧义。

ICC 和 VC++ 都可以编译您的代码。根据当前的措辞,它们是正确的:每一对都是独立处理的,并且由于size_<From+1>出现From在非推导上下文中([temp.deduct.type]/(5.3)),推导必然失败,因此size_<From+1>至少是专门化的但size_<To>反之则不然。因此,重载 (1) 比 (2) 更专业。

因此 ICC 和 VC++(大概)处理每个演绎对并得出结论,对于第二个演绎对,size_<To>至少不像 那样专业化size_<From+1>
Clang 和 GCC(大概)认为,对于 (1),From是从第一个参数推导出来的,因此不需要在第二对中推导出来,因为size_<To>它至少与它的对应项一样专业。