为什么std::distance无法处理const和非const迭代器的混合?

17

就像问题所述,我想知道原因。因为当我尝试获取 const 和非 const 迭代器之间的距离时,会出现错误。

vector<int> v;
auto it=v.begin();
auto cit=v.cbegin();
distance(it,cit);


no matching function for call to ‘distance(__gnu_cxx::__normal_iterator<int*, std::vector<int> >&, __gnu_cxx::__normal_iterator<const int*, std::vector<int> >&)

根据我有限的迭代器理解,我看不出为什么它不能工作。

4个回答

23

在调用std::distance函数时,您使用了可变迭代器和常量迭代器,因此模板参数推导失败。您可以通过明确指定模板参数来解决此问题。

std::vector<int> v;
auto i1 = v.begin();
auto i2 = v.cbegin();

auto dist = std::distance<std::vector<int>::const_iterator>( i1, i2 );

7
那是因为 std::distance() 只有一个模板参数:
template <class InputIterator>
iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last);

因此,firstlast必须可转换为相同的类型,但模板解析不会考虑vector<int>::iterator可以转换为vector<int>::const_iterator

他们为什么不创建带有2个模板参数的模板呢?在C++核心语言中是否可以实现?我的问题是这是一个设计决策还是语言限制? - NoSenseEtAl
要明确的是,我知道他们可以使用2个模板参数制作模板,但我想知道这是否会与1个模板参数版本发生冲突。 - NoSenseEtAl
@NoSenseEtAl,我会说这是设计决策。这样更简单,并且计算不同类型的迭代器(例如随机访问迭代器和前向迭代器)之间的距离可能不是您经常想要做的事情。您确实可以编写一个具有两个模板参数的版本,但那解决了什么实际问题呢? - Frédéric Hamidi
@NoSenseEtAl:它不会冲突,你完全可以定义自己的双参数版本(当然不能在std中)。这只是标准中许多细节之一,可能下一个版本会修复它。 - Mike Seymour
3
firstlast必须具有相同的类型,或者可以转换为相同的类型。”方便的是,标准要求vector::iterator可以转换为vector::const_iterator - Robᵩ
@Rob,没错,我太简单化了。回答已相应更新,谢谢 :) - Frédéric Hamidi

4

众所周知,std::distance只接受一个迭代器类型,而模板参数推导无法确定应该选择哪个类型(尽管只有一种类型是可能的,因为iterator可以转换为const_iterator,但不反过来)。

也许值得编写这样一个模板:

template <typename Container>
typename Container::const_iterator constify(const Container &, typename Container::iterator it) {
    return it;
}

然后,您可以像这样强制模板推断:
std::distance(constify(v, it), cit);

不需要写出冗长的类型名称。 Container& 参数很糟糕,因为据我所知,仅从迭代器参数中无法推断出Container


3

std::distance可以与这两个迭代器一起使用,但不起作用的是模板参数推断。编译器试图解析要替换为第一个模板参数的类型,并具有两个潜在的候选项,根据标准,这最终导致失败。

您可以采取以下两种方法之一:仅比较相同类型的迭代器或为模板提供类型:

std::distance<std::vector<int>::const_iterator>( v.begin(), v.cbegin() );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接