Std::iterator как параметр функции

У меня есть следующий фрагмент кода:

//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 в заголовочном файле.

Очевидно, что мое понимание концепции итератора ошибочно.

Может ли кто-нибудь указать, что не так с использованием?

ТИА

Вы читали руководство для std::iterator? Это вспомогательный класс для написания собственных итераторов (и он устарел), а не для передачи параметров функциям. И это шаблон, а вы пытаетесь использовать его без аргументов шаблона. Функции, получающие итераторы, должны быть шаблонами с типом итератора в качестве параметра шаблона.

HolyBlackCat 02.08.2023 09:03

Я предлагаю вам использовать тот же метод, что и все стандартные библиотечные функции: Templates. Как в template<typename IteratorT> bool per_scan(IteratorT,IteratorT);

Some programmer dude 02.08.2023 09:07

не размещайте объявления using в заголовках. Вы не using namespace std;, но если вы продолжите использовать каждый тип из std, который появляется в вашем коде, эффект будет таким же. См. Почему «используя пространство имен std;» считается плохой практикой?. Также учтите, что это нагружает читателя. Для каждого имени я должен обратиться к вашему списку объявлений использования, прежде чем я смогу узнать, к чему оно относится. Чистый код не требует, чтобы читатель переходил в разные места, чтобы понять одно место в коде.

463035818_is_not_an_ai 02.08.2023 09:35

Итераторы в C++ не полиморфны, и даже если бы они были, полиморфизм работает только с указателями и ссылками. В отличие от других языков, таких как Java или Python, переменные в C++ по умолчанию имеют семантику значений, а не семантику ссылок.

Miles Budnek 02.08.2023 10:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Да, ваше понимание ошибочно. Ваше использование шаблона 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 02.08.2023 10:50

@ 463035818_is_not_an_ai Спасибо! Я сам мало использовал C++20. Делаю первые шаги :-)

Ted Lyngmo 02.08.2023 10:53

Другие вопросы по теме