为什么以下代码使用非const迭代器为该行编译,但 const iterator (使用Visual Studio 2008)失败?
#include <vector>
using std::vector;
int main(int argc, char* argv[])
{
vector<int> test;
test.push_back(1);
test.push_back(2);
vector<int>::const_iterator cit = test.end();
std::distance(test.begin(), cit); // error: template parameter is ambiguous
vector<int>::iterator it = test.end();
std::distance(test.begin(), it);
return 0;
}
注意:在Visual Studio 2008中,没有矢量成员函数cbegin()
来避免模糊,但是重载begin()
方法:
iterator begin()
{ // return iterator for beginning of mutable sequence
return (iterator(_Myfirst, this));
}
const_iterator begin() const
{ // return iterator for beginning of nonmutable sequence
return (const_iterator(_Myfirst, this));
}
答案 0 :(得分:2)
模板distance
只接受一个参数distance<T>(T first, T last)
。由于test.begin()
的类型为iterator
而cit
的类型为const_iterator
,因此无法推断出模板参数。
您可以使用test.cbegin()
来获得有保证的const_iterator
,或者说static_cast<std::vector<int> const &>(test).begin()
。
(这与你max<T>(T x, T y)
并试图说max(1, 2U)
一样 - 它不会编译,因为它不明确。)
答案 1 :(得分:1)
注意:在Visual Studio 2008中,没有矢量成员函数
cbegin()
来避免模糊,但是重载begin()
方法:
我认为编译器总是选择非const对象的非const重载,而const方法只选择const对象。
调用
std::distance(test.begin(), cit);
不查看begin
的重载集和cit
的类型,并确定它是否可以匹配。它首先解决了过载(到了非const版本),因此失败了。
表达你的意图的最简洁的方法也可能适用于编译器:
vector<int> const &cref = test;
vector<int>::const_iterator cit = cref.end();
std::distance(cref.begin(), cit);
答案 2 :(得分:0)
功能模板std::distance
只需一个模板
参数,对于两个函数参数必须相同。该
返回类型test.begin()
只是iterator
,而不是const_iterator
std::vector<int>::iterator
,因此函数参数的类型不同。
编译器为第一个推导出std::vector<int>::const_iterator
,并且
cbegin
为第二个,所以扣除
失败。模板参数推断不会考虑到
可能的转换,除了最简单的转换。
有许多方法可以解决问题,但它们都很明显
缺点。 (这可能是委员会添加cend
和。{
const
函数。)目前,您最好的选择可能就是放弃iterator
,并使用{{1}}。
答案 3 :(得分:0)
distance
必须同时具有模板参数。在这种情况下,它是_Vector_const_iterator
。 begin
有两个重载:const和非const。 const-version生成_Vector_const_iterator
,但另一个生成_Vector_iterator
。 _Vector_iterator
继承自_Vector_const_iterator
。
因此,begin
的const和非const重载都能够生成_Vector_const_iterator
,并且它们都可以被选为非const对象,即编译器会混淆。
这就是我编译的方式:
std::distance(((const vector<int>&)test).begin(), cit);