const 指针的模板参数推导失败

Template argument deduction failing for const pointers

我不明白为什么在这种情况下模板参数推导失败:

template<class Iterator> void
f(Iterator x, const Iterator y) {}

int main()
{
    const int* cpi;
    int* pi;
    f(pi,cpi);
}

为什么第二个参数Iterator不推导出int*

f最地道的声明是什么?

迭代器可以是 int *const int *。第二个函数参数的限定符 const 表示 int * constconst int * const.

您可以创建特征来检查迭代器是否是常量值的迭代器。

#include <iterator>    // iterator_traits
#include <type_traits> // is_const_v, remove_pointer_t, enable_if_t

template<typename T>
struct is_const_iterator {
    // Define a pointer type to the type iterated over. Something already a pointer
    // will still be a pointer
    using pointer = typename std::iterator_traits<T>::pointer;

    // Remove the pointer part from the type and check for constness.
    static const bool value = std::is_const_v<std::remove_pointer_t<pointer>>;
};

// Helper variable template to simplify the use of the above.
template<class T>
inline constexpr bool is_const_iterator_v = is_const_iterator<T>::value;

SFINAE 使用 is_const_iterator_v

template<class It, class CIt, std::enable_if_t<is_const_iterator_v<CIt>, int> = 0>
void f(It x, CIt y) {
    //for(; x != y; ++x) std::cout << *x << '\n';
}

或者,如果您的函数没有其他重载(不需要 SFINAE),您可以使用 static_assert 让用户更清楚:

template<class It, class CIt>
void f(It x, CIt y) {
    static_assert(is_const_iterator_v<CIt>, "Arg 2 must be a const iterator");
    //for(; x != y; ++x) std::cout << *x << '\n';
}

示例:

#include <iostream>
#include <vector>

int main() {
    int values[]{1, 2};

    int* pi = values;
    const int* cpi = values + std::size(values);

    std::vector<int> v{3, 4};

    f(pi, cpi);
    f(v.begin(), v.cend());
    // f(pi, pi);             // error, pi is non-const
    // f(v.begin(), v.end()); // error v.end() is non-const
}