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

Me *_*d I 5 c++ c++11

在下面的程序中,两个函数调用都打印"非整数过载",即使我有一个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"
}
Run Code Online (Sandbox Code Playgroud)

我甚至尝试过使用enable_if<!std::is_integral<...>>第二次超载,但无济于事.

Dan*_*rey 8

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

如果要提取迭代器类型指向的类型,则应使用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;
}
Run Code Online (Sandbox Code Playgroud)

!在第二个上使用相同的附加内容.这更具描述性,因为代码很清楚它的作用.

实例


Cas*_*sey 6

对于迭代器类型foo,decltype(*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;
}
Run Code Online (Sandbox Code Playgroud)

这将导致您的其他重载模糊,因为两者现在都匹配.您需要按照OP中的建议约束第二个重载.