请考虑以下事项:
#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>{});
}
gcc和clang都认为这个电话不明确。为什么? (1)
比(2)
更专业吗?
注意:我知道这可以通过enable_if_t<(To > From+1)>
投入额外的(2)
轻松解决,但我不会想到我需要这样做。
答案 0 :(得分:3)
这一点 - 不出所料 - 通过CWG问题中的类似示例解决,即#455:
如果其中一个参数是非deuced,那么部分排序 应该只考虑专业化的类型:
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
根据我的推理#9应该会产生第二对的歧义 是(T,长*)。第二种类型(即长*)取自 #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>
是专门的,因为它是对应物。