У меня есть следующий фрагмент кода:
//code.h
#include<string>
#include<iterator>
#include<iostream>
using std::string;
using std::advance;
using std::iterator;
using std::cin;
using std::cout;
using std::endl;
bool chk_if_uniq (string);
bool per_scan(iterator,iterator);
//code.cpp
#ifndef CODE_H
#define CODE_H
#include "code.h"
#endif
int main (){
string input_string;
cout << "enter string: ";
cin >> input_string;
auto result = chk_if_uniq(input_string);
if (result){
cout << input_string << " contains unique characters." << endl;
}
else{
cout << input_string << " contains non-unique characters." << endl;
}
return 0;
}
bool chk_if_uniq (string s){
auto bIter = s.begin();
auto eIter = s.end();
bool iterPos = (bIter != eIter);
auto flag = true;
while(iterPos){
flag = per_scan(bIter,eIter);
if (!flag){
break;
}
advance(bIter,1);
}
return flag;
}
bool per_scan(iterator it, iterator eIter){
auto nxIt = it;
bool iterPos = (nxIt != eIter);
auto flag = true;
do{
++nxIt;
if (iterPos){
if (*nxIt == *it){
flag = false;
}
}
}while(flag);
return flag;
}
У меня есть следующая команда компиляции:
g++ -ggdb -g3 -o -pedantic-errors -std=c++17 -Wall -Wextra -Wpedantic
Я использую версию gcc 8.4.1.
Я получаю следующие ошибки компилятора:
In file included from code.cpp:3:
code.h:13:15: error: ‘auto’ parameter not permitted in this context
bool per_scan(iterator,iterator);
^~~~~~~~
code.h:13:24: error: ‘auto’ parameter not permitted in this context
bool per_scan(iterator,iterator);
^~~~~~~~
code.cpp: In function ‘bool chk_if_uniq(std::__cxx11::string)’:
code.cpp:33:31: error: too many arguments to function ‘bool per_scan()’
flag = per_scan(bIter,eIter);
^
In file included from code.cpp:3:
code.h:13:6: note: declared here
bool per_scan(iterator,iterator);
^~~~~~~~
code.cpp: At global scope:
code.cpp:43:24: error: ‘auto’ parameter not permitted in this context
bool per_scan(iterator it, iterator eIter){
^~
code.cpp:43:37: error: ‘auto’ parameter not permitted in this context
bool per_scan(iterator it, iterator eIter){
^~~~~
code.cpp: In function ‘bool per_scan()’:
code.cpp:45:15: error: ‘it’ was not declared in this scope
auto nxIt = it;
^~
code.cpp:45:15: note: suggested alternative: ‘int’
auto nxIt = it;
^~
int
code.cpp:46:27: error: ‘eIter’ was not declared in this scope
bool iterPos = (nxIt != eIter);
^~~~~
code.cpp:46:27: note: suggested alternative: ‘extern’
bool iterPos = (nxIt != eIter);
^~~~~
extern
Как видно из журнала ошибок, все ошибки возникают из-за использования iterator в качестве типа параметра для метода per_scan в заголовочном файле.
Очевидно, что мое понимание концепции итератора ошибочно.
Может ли кто-нибудь указать, что не так с использованием?
ТИА
Я предлагаю вам использовать тот же метод, что и все стандартные библиотечные функции: Templates. Как в template<typename IteratorT> bool per_scan(IteratorT,IteratorT);
не размещайте объявления using в заголовках. Вы не using namespace std;, но если вы продолжите использовать каждый тип из std, который появляется в вашем коде, эффект будет таким же. См. Почему «используя пространство имен std;» считается плохой практикой?. Также учтите, что это нагружает читателя. Для каждого имени я должен обратиться к вашему списку объявлений использования, прежде чем я смогу узнать, к чему оно относится. Чистый код не требует, чтобы читатель переходил в разные места, чтобы понять одно место в коде.
Итераторы в C++ не полиморфны, и даже если бы они были, полиморфизм работает только с указателями и ссылками. В отличие от других языков, таких как Java или Python, переменные в C++ по умолчанию имеют семантику значений, а не семантику ссылок.





Да, ваше понимание ошибочно. Ваше использование шаблона std::iterator напоминает дженерики в Java, которые являются заполнителями для конкретных типов. Они основаны на стирании шрифта. С другой стороны, шаблоны можно использовать для стирания шрифта, но они не делают этого из коробки. Шаблон класса должен быть создан, прежде чем его можно будет использовать. Тип параметра функции — это тип, а не шаблон. Этот
bool per_scan(std::iterator,std::iterator);
Не имеет смысла, потому что std::iterator не является типом.
Более того, std::iterator предназначен для использования в качестве помощника при реализации пользовательских итераторов. Использование экземпляра std::iterator в качестве параметра функции редко бывает полезным, поскольку он ограничивает тип параметра экземплярами шаблона std::iterator, но не все итераторы подходят для этого. На самом деле я не знаю ни одного итератора в стандартной библиотеке, который является экземпляром std::iterator. Одним из преимуществ итераторов является то, что большую часть времени вам не нужно заботиться о конкретном типе. Например, std::vector::iterator можно реализовать как указатель. Вам все равно.
Рассмотрим, например, как объявляются стандартные алгоритмы. Тип итераторов обычно является аргументом шаблона, который не делает предположений о деталях реализации (например, std::find ). Требования к реализации определяются в именованных требованиях или через концепции (начиная с C++20). См. https://en.cppreference.com/w/cpp/named_req/Iterator.
Измените функцию на шаблон функции:
template <typename Iter>
bool per_scan(Iter it, Iter eIter){
auto nxIt = it;
bool iterPos = (nxIt != eIter);
auto flag = true;
do{
++nxIt;
if (iterPos){
if (*nxIt == *it){
flag = false;
}
}
}while(flag);
return flag;
}
std::iterator — это (устаревший) шаблон класса, который использовался в качестве вспомогательного класса при создании классов итераторов. То, что вы ищете, вероятно, называется concept под названием std::input_iterator:
bool per_scan(std::input_iterator auto it, std::input_iterator auto eIter)
Однако ваша реализация per_scan ошибочна и вызывает переполнение буфера стека. Я предлагаю использовать std::find вместо per_scan:
#include <algorithm>
bool chk_if_uniq(const std::string& s) {
for (auto bIter = s.begin(), eIter = s.end(); bIter != eIter; ++bIter) {
// replace `per_scan` with `std::find`:
if (std::find(std::next(bIter), eIter, *bIter) != eIter) return false;
}
return true;
}
В качестве альтернативы используйте std::string::find:
bool chk_if_uniq(const std::string& s) {
for(std::size_t idx = 0; idx < s.size(); ++idx) {
if (s.find(s[idx], idx + 1) != std::string::npos) return false;
}
return true;
}
Я не активно использую С++ 20. Если у меня нет времени погрузиться в него, я предпочитаю не использовать его в ответах и оставлять для других, которые знают, о чем говорят. +1.
@ 463035818_is_not_an_ai Спасибо! Я сам мало использовал C++20. Делаю первые шаги :-)
Вы читали руководство для
std::iterator? Это вспомогательный класс для написания собственных итераторов (и он устарел), а не для передачи параметров функциям. И это шаблон, а вы пытаетесь использовать его без аргументов шаблона. Функции, получающие итераторы, должны быть шаблонами с типом итератора в качестве параметра шаблона.