繁体   English   中英

auto it = vector.begin()结果类型不能转换为const_iterator

[英]auto it = vector.begin() resulting type is not convertible to const_iterator

容器需要提供iterator类型,该类型可以隐式转换为const_iterator 鉴于此,我试图使用auto通过vector::begin()初始化一个对象,并在std::distance中使用该结果对象,其中RHS是一个const_iterator 这不起作用。 这是一个完整的例子:

#include <cstdlib>
#include <vector>
#include <iterator>
#include <iostream>

typedef std::vector <char> Packet;
typedef std::vector <Packet> Packets;

template <typename Iter> 
Iter next_upto (Iter begin, Iter end, size_t n)
{
    Iter ret = begin;
      for (; n > 0 && ret != end; ++ret, --n)
            ;   
        return ret;
}

Packets::const_iterator Process (Packets::const_iterator begin, Packets::const_iterator end)
{
  Packets::const_iterator ret = begin;
  while (ret != end)
    ++ret;  // do something
  return ret;
}

int main()
{
  Packets test (100); // vector of 100 default-initialized packets

  // process them 10 at a time
  for (auto it = test.begin();
    it != test.end();
    it = next_upto (it, test.end(), 10))
  {
     auto itr = Process (it, next_upto (it, test.end(), 10));
     Packets::const_iterator it2 = it; 
     const size_t n1 = std::distance (it2, itr);
     const size_t n = std::distance (it, itr);
     std::cout << "Processed " << n << " packets\n";
  }
}

在g ++ 4.8.1(和4.8.2)下编译,得到:

[1/2] Building CXX object CMakeFiles/hacks.dir/main.o
FAILED: /usr/bin/g++    -Wall -std=c++11 -g -MMD -MT CMakeFiles/hacks.dir/main.o -MF "CMakeFiles/hacks.dir/main.o.d" -o CMakeFiles/hacks.dir/main.o -c main.cpp
main.cpp: In function ‘int main()’:
main.cpp:39:45: error: no matching function for call to ‘distance(__gnu_cxx::__normal_iterator<std::vector<char>*, std::vector<std::vector<char> > >&, __gnu_cxx::__normal_iterator<const std::vector<char>*, std::vector<std::vector<char> > >&)’
      const size_t n = std::distance (it, itr);
                                             ^
main.cpp:39:45: note: candidate is:
In file included from /usr/include/c++/4.8/bits/stl_algobase.h:66:0,
                 from /usr/include/c++/4.8/vector:60,
                 from main.cpp:2:
/usr/include/c++/4.8/bits/stl_iterator_base_funcs.h:114:5: note: template<class _InputIterator> typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator)
     distance(_InputIterator __first, _InputIterator __last)
     ^
/usr/include/c++/4.8/bits/stl_iterator_base_funcs.h:114:5: note:   template argument deduction/substitution failed:
main.cpp:39:45: note:   deduced conflicting types for parameter ‘_InputIterator’ (‘__gnu_cxx::__normal_iterator<std::vector<char>*, std::vector<std::vector<char> > >’ and ‘__gnu_cxx::__normal_iterator<const std::vector<char>*, std::vector<std::vector<char> > >’)
      const size_t n = std::distance (it, itr);
                                             ^

我知道,我可以通过调用解决这种特定情况下cbegin()cend()而不是begin()end() ,但由于begin()end()返回一个类型,应该是转换为const_iterator ,我我不确定我理解为什么需要它。

为什么auto在这种情况下推断出一种不能转换为const_iterator

您的问题可以简化为以下示例,由于相同的原因,该示例失败。

#include <vector>
#include <iterator>
int main()
{
    std::vector<int> v;
    std::vector<int>::const_iterator it1 = v.begin();
    auto it2 = v.end();
    auto n = std::distance(it1, it2);
}

std::distance是使用两个参数的相同模板参数类型定义的,并且模板参数推断失败,因为您有一个const_iteratoriterator

在从函数调用中推导出模板参数时,不考虑用户定义的转换,并且由于这两个参数在这种情况下具有不同的类型,并且两者都参与模板参数推导,因此推导失败。

§14.8.1/ 6 [temp.arg.explicit]

如果参数类型不包含参与模板参数推导的模板参数 ,则将对函数参数执行隐式转换(第4节)以将其转换为相应函数参数的类型。

§14.8.2.1/ 4 [temp.over]

... [ 注意:如14.8.1中所述,如果参数不包含参与模板参数推导的模板参数 ,则将对函数参数执行隐式转换,以将其转换为相应函数参数的类型。 除了前面列表中描述的转换之外,还允许这样的转换。 - 尾注 ]

您需要将iterator转换为const_iterator ,或者将模板参数明确指定为std::distance

auto n = std::distance(it1, static_cast<decltype(it1)>(it2));

要么

auto n = std::distance<decltype(it1)>(it1, it2);

当然,其他选项是不使用auto并在两种情况下显式指定迭代器类型,或者在需要确保类型为const_iterator时使用vector::cbegin()vector::cend() vector::cbegin() vector::cend()成员函数。

这个问题与迭代器转换没什么共同之处。 编译器无法确定模板参数。 你写的也是一样的

int x = 10;
long y = 20;

std::cout << std::max( x, y ) << std::endl;

虽然int类型的对象可以隐式转换为long类型的对象。

至于你的例子,你可以写

const size_t n = std::distance<std::vector<char>::const_iterator> (it, itr);

为什么自动推断出一个典型[在这种情况下不能转换为const_iterator?

  • begin()有两个可用的重载:

签名:

iterator begin();

const_iterator begin() const;

你将你的向量声明为Packets test (100); ,这是非常数。

如果将其声明为const,则auto类型推导将使第二个begin()重载作为最佳(和唯一)匹配。

它编译并运行这个简单的修复程序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM