2017-02-16 28 views
2

Бывают случаи, когда я хочу использовать итератор, возвращаемый функцией из библиотеки алгоритмов. Проблема, с которой я сталкиваюсь, возникает, когда я переключаюсь между изменяющей функцией и немодулирующей функцией. Причина в не изменяющейся функции я хочу использовать const_iterator. Как игрушечный пример:Есть ли make_const_iterator?

vector<int> v = { 1, 8, 7, 4, 3, 6, 2, 5 }; 
auto it = partition(begin(v), end(v), bind(greater<int>(), placeholders::_1, 3)); 

cout << (find(cbegin(v), it, 13) != cend(v)) << endl; 

Когда я пытаюсь скомпилировать этот код, я получаю ошибку:

no matching function for call to find(std::vector<int>::const_iterator, __gnu_cxx::__normal_iterator<int*, std::vector<int> >&, int)

Проблема Я бегу в это единственный процесс преобразования я могу найти потенциально дорого: auto cit = next(cbegin(v), distance(begin(v), it))

Есть ли способ, которым я могу сделать эту работу? Или я застрял преобразование или просто используя не const_iterator s?

+0

Просто упреждающий комментарий, я знаю, что я мог бы просто использовать 'find' непосредственно на' V'. Я не ищу лучшего способа написать свой пример с игрушкой; Я ищу решение проблемы, которую он иллюстрирует. –

+0

Вы пытались просто построить const_iterator из обычного? – rubenvb

+0

Можно ли предположить, что тип исходного контейнера неизвестен? Если нет, 'decltype (v) :: const_iterator (it)' делает трюк. Использование 'cvegin (v)' в предлагаемом решении, по-видимому, подразумевает, что у вас есть доступ к 'v', а не только к итератору. –

ответ

3

Это гораздо дешевле просто бросить изменяемый итератор к постоянному итератора:

cout << (find(cbegin(v), vector<int>::const_iterator{it}, 13) 
     != cend(v)) << endl; 

Изменяемый итератор всегда должен быть литьевым в постоянный итератор.

EDIT: Я нашел часть стандарта, которая гарантирует, что итератор конвертируется в постоянный итератор.

Таблица 96 в разделе 23.2 "Требования Container" указывает, что выражение X::iterator результаты:

any iterator category that meets the forward iterator requirements. convertible to X::const_iterator.

+1

Есть ли гарантированное такое преобразование? –

+1

@ Cheersandhth.-Alf См. Здесь: http://stackoverflow.com/a/7759474/1294207 –

+1

@FantasticMrFox: Это фантастика, спасибо. Я доверяю хорошему роботу. Но стандартная ссылка. заставило бы это сделать. –

4

Вы можете указать аргумент шаблона:

find<decltype(cbegin(v))>(cbegin(v), it, 13) != cend(v) 

Demo

+2

Я вижу, что ошибка на самом деле потому, что я вызываю двусмысленность в выводе шаблона 'find'. Так что это то же самое, что и другие примеры, заставляя бросить. Есть ли какое-либо заявление в любом месте, что такой актер является законным, а не только определенной реализацией? –

1

Есть три подходы.

Первый из них должен написать

cout << (find(begin(v), it, 13) != cend(v)) << endl; 
       ^^^^^ 

Второй заключается в написании

cout << (find(cbegin(v), static_cast<std::vector<int>::const_iterator>(it) 
, 13) != cend(v)) << endl; 

или короче

cout << (find(cbegin(v), static_cast<decltype(v.cbegin())>(it) 
, 13) != cend(v)) << endl; 

И третье, чтобы написать

cout << (find<std::vector<int>>::const_iterator>(cbegin(v), it, 13) != cend(v)) << endl; 

или короче

cout << (find<decltype(v.cbegin())>(cbegin(v), it, 13) != cend(v)) << endl; 
+0

Да, я упоминаю в вопросе, что ** 1 ** нежелательно. Остальные 2 варианта эффективно кастуют в 'const_iterator' (который я не знал, что вы могли бы сделать.) Есть ли что-нибудь в стандарте, которое явно разрешает это? –

+1

@ JonathanMee См. В таблице 96 - Требования к контейнеру - строка об итераторах. –