auto it = vector.begin() 结果类型不可转换为 const_iterator [英] auto it = vector.begin() resulting type is not convertible to const_iterator

查看:72
本文介绍了auto it = vector.begin() 结果类型不可转换为 const_iterator的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Containers are required to provide an iterator type which is implicitly convertible to a const_iterator. Given this, I am trying to use auto to initialize an object via vector::begin(), and use that resulting object in std::distance where the RHS is a const_iterator. This isn't working. Here is a complete example:

#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
";
  }
}

在 g++ 4.8.1(和 4.8.2)下编译这个产量:

Under g++ 4.8.1 (and 4.8.2) compiling this yields:

[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,我不确定我是否理解为什么需要这样做.

I'm aware that I can fix this particular instance by calling cbegin() and cend() rather than begin() and end(), but since begin() and end() return a type that should be convertible to const_iterator, I'm not sure I understand why this is needed.

为什么在这种情况下 auto 会推导出一个不能转换为 const_iterator 的类型?

Why does auto deduce a type in this case that is not convertible to const_iterator?

推荐答案

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

Your problem can be reduced to the following example, which fails for the same reasons.

#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.

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

User defined conversions are not considered when deducing template arguments from function calls, and since the two arguments have different types in this case, and both are participating in template argument deduction, the deduction fails.

§14.8.1/6 [temp.arg.explicit]

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

Implicit conversions (Clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction.

§14.8.2.1/4 [temp.over]

... [ 注意: 如14.8.1中所规定,将对函数实参进行隐式转换,将其转换为对应函数参数的类型如果参数不包含参与模板参数推导的模板参数.除了前面列表中描述的转换之外,还允许进行此类转换.—结束注释 ]

... [ Note: as specified in 14.8.1, implicit conversions will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter contains no template-parameters that participate in template argument deduction. Such conversions are also allowed, in addition to the ones described in the preceding list. —end note ]

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

You'll need to convert the iterator to const_iterator, or specify the template argument to std::distance explicitly.

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

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

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

Other options are, of course, to not use auto and explicitly specify the iterator type in both cases, or use the vector::cbegin() and vector::cend() member functions when you need to ensure that the type is a const_iterator.

这篇关于auto it = vector.begin() 结果类型不可转换为 const_iterator的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆