std::iterator 作为函数参数

std::iterator as function parameter

提问人:Vinod 提问时间:8/2/2023 更新时间:8/2/2023 访问量:107

问:

我有以下一段代码:

//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

从错误日志中可以明显看出,所有错误都源于在头文件中用作方法的参数类型。iteratorper_scan

显然,我对迭代器概念的理解是有缺陷的。

有人可以指出用法有什么问题吗?

短暂性投资安全

C++ 函数 迭代器 参数传递

评论

8赞 HolyBlackCat 8/2/2023
你读过手册吗?它是一个用于编写自己的迭代器的帮助类(它已被弃用),它不用于将参数传递给函数。它是一个模板,而您尝试在没有模板参数的情况下使用它。接收迭代器的函数应为模板,迭代器类型为模板参数。std::iterator
3赞 Some programmer dude 8/2/2023
我建议您使用与所有标准库函数相同的方法:模板。如template<typename IteratorT> bool per_scan(IteratorT,IteratorT);
1赞 463035818_is_not_an_ai 8/2/2023
不要将 using 声明放在标头中。你不是,但如果你继续使用代码中出现的每个类型,那么效果是一样的。请参阅为什么“使用命名空间 std;”被视为不良做法?。还要考虑到它会给读者带来负担。对于每个名称,我必须先查看您的使用声明列表,然后才能知道它指的是什么。干净的代码不需要读者跳转到不同的地方来理解代码中的一个地方using namespace std;std
0赞 Miles Budnek 8/2/2023
C++ 中的迭代器不是多态的,即使它们是多态的,多态性也仅适用于指针和引用。与 Java 或 Python 等其他语言不同,默认情况下,C++ 中的变量具有值语义,而不是引用语义。

答:

3赞 463035818_is_not_an_ai 8/2/2023 #1

是的,你的理解是有缺陷的。您对模板的使用让人想起 Java 中的泛型,它们是具体类型的占位符。它们基于类型擦除。另一方面,模板可用于类型擦除,但它们不是开箱即用的。类模板必须先实例化,然后才能使用。函数的参数类型是类型,而不是模板。这std::iterator

bool per_scan(std::iterator,std::iterator);

没有意义,因为 std::iterator 不是一个类型。

此外,在实现自定义迭代器时用作帮助程序。使用 as 函数参数的实例化几乎没有用处,因为它将参数类型限制为模板的实例化,但并非所有迭代器都符合这一点。实际上,我不知道标准库中有任何迭代器是 的实例化。迭代器的一个优点是,大多数时候你不需要关心具体类型。例如,可以实现为指针。你不需要在意。std::iteratorstd::iteratorstd::iteratorstd::iteratorstd::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;
}

现场演示

4赞 Ted Lyngmo 8/2/2023 #2

std::iterator是一个(已弃用的)类模板,在创建迭代器类时用作帮助程序类。你要找的可能是一个叫做std::input_iteratorconcept

bool per_scan(std::input_iterator auto it, std::input_iterator auto eIter)

但是,您的实现存在缺陷,并导致堆栈缓冲区溢出。我建议使用 std::find 而不是:per_scanper_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;
}

评论

0赞 463035818_is_not_an_ai 8/2/2023
我没有积极使用 c++20。除非我有时间深入研究它,否则我宁愿不在答案中使用它,而是把它留给那些知道他们在说什么的人。+1.
0赞 Ted Lyngmo 8/2/2023
@463035818_is_not_an_ai 谢谢!我自己没怎么用过C++20。迈出我的第一个婴儿步:-)