返回迭代器到C数组的方法的正确类型声明

Correct type declaration for method returning iterator to C array

本文关键字:类型 声明 方法 返回 数组 迭代器      更新时间:2023-10-16

我可以这样遍历一个c风格的数组:

char foo[3] = { 'a', 'b', 'c' };
for (auto it = std::begin(foo); it != std::end(foo); ++it)
{
    *it = 'k'; //values of foo are correctly modified
}

现在假设我想将数组包装在一个类中,并公开返回相对迭代器的begin()end()方法。我尝试了以下操作:

template<size_t size>
class StackMemPolicy
{
private:
    char mem[size];
public:
    typedef typename  std::iterator<std::input_iterator_tag, char> iter;
    iter  begin() 
    {
        return std::begin(mem);
    }
    iter  end()
    {
        return std::end(mem);
    }
 }

返回的类型声明似乎是错误的,下面的调用代码无法编译:

StackMemPolicy<4> bar;
for (auto it = bar.begin(); it != bar.end(); ++it)
{
    *it = 'k';
}

错误如下:

Error 1 Error C2678: binary '!=':没有找到带a的操作符类型'StackMemPolicy<4>::iter'的左操作数(或者没有)可接受的转换)

谁能告诉我我的错误在哪里?

std::iterator意味着被用作基类。从24.4.2/1:

namespace std {
  template<class Category, class T, class Distance = ptrdiff_t,
    class Pointer = T*, class Reference = T&>
  struct iterator {
    typedef T value_type;
    typedef Distance difference_type;
    typedef Pointer pointer;
    typedef Reference reference;
    typedef Category iterator_category;
  };
}

它只给你一些类型定义,不会神奇地实现所有必需的操作符。在您的情况下,begin()end()应该只返回char*,它已经有std::iterator_traits的专门化。

然而,如果你的迭代器必须更智能(例如,可能这是某种循环缓冲区),你就必须创建自己的迭代器类并实现所需的操作符。为了使该迭代器能够使用标准库中的各种特性(如std::iterator_traits),您需要预定义的类型,如value_typeiterator_category等。

由于正确使用这些参数有时会很棘手,因此std::iterator将根据给定的模板参数为您定义这些参数。下面是一个在迭代器中使用std::iterator_traits的例子。

请注意,从c++ 17开始,由于各种原因,std::iterator已被弃用。

如果我更改:

typedef typename  std::iterator<std::input_iterator_tag, char> iter;

:

typedef char * iter;

除非您不想修改行为,否则您应该只返回std::begin(mem),这只不过是char *

参见参见2' and overload

使用函数的尾随返回类型语法可以实现如下:

template<size_t size>
class StackMemPolicy
{
private:
    char mem[size];
public:
    //typedef typename  std::iterator<std::input_iterator_tag, char> iter;
     auto begin() -> decltype(std::begin(mem))
    {
        return std::begin(mem);
    }
     auto  end() -> decltype(std::end(mem))
    {
        return std::end(mem);
    }
 };
 int main()
 { 
    StackMemPolicy<3> bar;
    for (auto it = bar.begin(); it != bar.end(); ++it)
   {
     *it = 'k';
   }

    for (auto it = bar.begin(); it != bar.end(); ++it)
   {
     std::cout<<*it;
   }
 }