auto it = vector.begin () результирующий тип не конвертируется в 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?

4

Решение

Ваша проблема может быть сведена к следующему примеру, который терпит неудачу по тем же причинам.

#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_iterator а также iterator,

Определенные пользователем преобразования не учитываются при выводе аргументов шаблона из вызовов функций, и, поскольку в этом случае два аргумента имеют разные типы, и оба участвуют в выводе аргументов шаблона, вывод не выполняется.

§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 и явно укажите тип итератора в обоих случаях, или используйте vector::cbegin() а также vector::cend() функции-члены, когда вам нужно убедиться, что тип const_iterator,

18

Другие решения

Проблема не имеет ничего общего с преобразованием итератора. Компилятор просто не может определить аргумент шаблона. То же самое, если бы вы написали

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);
4

Почему в этом случае auto выводит тип [e, который не конвертируется в const_iterator?

  • У вас есть две доступные перегрузки для begin() :

Подписи:

iterator begin();

const_iterator begin() const;

Вы объявили свой вектор как Packets test (100);, который не является постоянным.

Если вы объявите это const, auto Тип вычета будет иметь второе begin() перегрузка как лучший (и уникальный) матч.

Он компилируется и запускается с этим простым исправлением..

1
По вопросам рекламы ammmcru@yandex.ru