为什么重载分辨率不选择第一个函数?

Why doesn't overload resolution pick the first function?

本文关键字:第一个 函数 选择 重载 分辨率 为什么      更新时间:2023-10-16

在下面的程序中,两个函数调用都打印"非积分重载",即使我有一个enable_if语句将函数限制为仅整型容器类型。为什么?

#include <iostream>
#include <vector>
#include <type_traits>
template<bool B, typename V = void>
using enable_if = typename std::enable_if<B, V>::type;
template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
    -> enable_if<std::is_integral<decltype(*first)>{}>
{
    std::cout << "Integral container type" << std::endl;
}
template<typename ForwardIt>
void f(ForwardIt, ForwardIt)
{
    std::cout << "Non-integral container type" << std::endl;
}
int main()
{
    struct X { };
    std::vector<int> iv;
    std::vector<X>   xv;
    f(iv.begin(), iv.end()); // "Non-integral container type"
    f(xv.begin(), xv.end()); // "Non-integral container type"
}

我什至尝试在第二次重载上使用enable_if<!std::is_integral<...>>但无济于事。

另一个答案已经解释了这个问题,但我认为有更好的解决方案。

如果要提取迭代器类型指向的类型,则应使用iterator_traits 。在代码中,将第一个重载更改为:

template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
    -> enable_if<std::is_integral<typename std::iterator_traits<ForwardIt>::value_type>{}>
{
    std::cout << "Integral container type" << std::endl;
}

并在第二个上使用相同的附加!。这更具描述性,因为代码非常清楚它的作用。

现场示例

对于迭代器类型 foodecltype(*foo) 将是foo::value_type& 。引用类型绝对不是整数的。在评估具有std::is_integral特征的类型之前,您需要删除引用(可能还有 cv 限定,IIRC),这很容易通过std::decay转换类型特征完成:

template<bool B, typename V = void>
using enable_if = typename std::enable_if<B, V>::type;
template<typename T>
using decay = typename std::decay<T>::type;
template<typename ForwardIt>
auto f(ForwardIt first, ForwardIt)
    -> enable_if<std::is_integral<decay<decltype(*first)>>{}>
{
    std::cout << "Integral container type" << std::endl;
}

这将导致与您的其他重载不明确,因为两者现在将匹配。您需要按照 OP 中的建议约束第二个重载。

相关文章: