在C++中将迭代器存储为类成员的最佳实践

Best practice to store an iterator as a class member in C++

本文关键字:成员 最佳 C++ 迭代器 存储      更新时间:2023-10-16

在迭代的序列或数据结构未知的情况下,是否有将迭代器存储为类成员的最佳实践?我写了一些代码来说明我试图实现的目标,但这些代码无法编译。

#include <iterator>
class entity {
    std::iterator<std::forward_iterator_tag, double>
        &it_begin_, &it_end_;
public:
    template <typename iter_type>
    entity(iter_type first, iter_type last) 
    : it_begin_(first)
    , it_end_(last) { } 
    // ... other implementation details
};
// example usage
int main() {
    std::vector<double> my_vec {1.0, 2.0, 6.0, 8.0, 2.0};
    entity my_entity(std::begin(my_vec), std::end(my_vec));
    // do stuff with entity
    return 0;
}

编辑:

只是为了添加一些上下文,我正试图按照我在CodeReview网站上收到的建议来实现一些东西。

编辑2:

我收到了一些有用的答案。请原谅我没有提到这个细节,但我认为从代码中可以清楚地看到:我想指定(作为实现细节的一部分)我想要一个前向迭代器,并且取消引用它会返回一个double

几件事:

  1. std::begin(my_vec)返回迭代器,但实体类在其上存储引用。如果要以这种方式使用它,请删除引用&

  2. 存储迭代器没有问题,但迭代器总是相对于像vector::iterator这样的容器类型。或者你可以为你的类模板:


template < class iterator > 
class entity
{
  iterator _it, _end;
public:
  entity(iterator begin, iterator end): _it(begin), _end(end){}
  /* ... */
};
int main() {
  std::vector<double> my_vec {1.0, 2.0, 6.0, 8.0, 2.0};
  entity my_entity(my_vec.begin(), my_vec.end());
  // do stuff with entity
  return 0;
}

您可以使用类模板和辅助函数模板来做您想做的事情。

template <typename iter_type>
class entity {
   iter_type it_begin_;
   iter_type it_end_;
   public:
   entity(iter_type first, iter_type last) 
      : it_begin_(first), it_end_(last) { } 
};
template <typename iter_type>
entity<iter_type> make_entity(iter_type first, iter_type last)
{
   return entity<iter_type>(first, last);
}

示例用法:

#include <iterator>
#include <vector>
#include <map>
int main()
{
   std::vector<double> my_vec {1.0, 2.0, 6.0, 8.0, 2.0};
   auto my_entity1 = make_entity(std::begin(my_vec), std::end(my_vec));
   // do stuff with entity
   std::map<int, double> my_map;
   auto my_entity2 = make_entity(std::begin(my_map), std::end(my_map));
   // do stuff with entity
   return 0;
}

编辑

为了确保迭代器是一个正向迭代器,并且包含的类型是double,可以使用:

template <typename T> struct is_type_double : public std::false_type {};
template <> struct is_type_double<double> : public std::true_type {};
template <> struct is_type_double<double&> : public std::true_type {};
template <typename iter_type>
class entity {
   iter_type it_begin_;
   iter_type it_end_;
   public:
   entity(iter_type first, iter_type last) 
      : it_begin_(first), it_end_(last)
   {
      static_assert(is_type_double<decltype(*first)>::value, "Problem.");
   } 
};
template <typename iter_type>
entity<iter_type> make_entity(iter_type first, iter_type last)
{
   return entity<iter_type>(first, last);
}

有了它,你可以使用:

std::vector<double> my_vec {1.0, 2.0, 6.0, 8.0, 2.0};
auto my_entity1 = make_entity(std::begin(my_vec), std::end(my_vec));

如果你使用,你会得到一个编译时错误

std::map<int, double> my_map;
auto my_entity2 = make_entity(std::begin(my_map), std::end(my_map));