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

时间:2015-09-01 15:30:33

标签: c++ templates c++11 overloading

请考虑以下事项:

#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)轻松解决,但我不会想到我需要这样做。

1 个答案:

答案 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>是专门的,因为它是对应物。