如何迭代(在类外部)作为向量的私有成员<unique_ptr <t >>

时间:2018-09-13 09:46:24

标签: c++ c++11

class Organization {
 private:
  vector<unique_ptr<Employee>> employees_;
  vector<unique_ptr<Item>> items_;
}org;

我需要在课堂之外有一个设施来遍历员工和物品并打电话给他们的成员,如下所示...

for(auto const& e : getEmployees()) { e.get()->getName(); } 

但是我无法使getEmployees()函数返回employees_,因为unique_ptrs的向量不可复制

所以我目前有一个for_each_employee函数

template<class callable>
void Organization::for_each_employee(callable f) {
     for(auto const& e : employees_) {
        f(e.get());
   }
}

// And I use it like,
org.for_each_employee([](Employee* e){ e->getName(); });

但是我不喜欢这个主意,因为我不得不写for_each_employee和for_each_item。我有其他类似结构的类。因此,我最终将编写许多for_each_XX类型的函数。这不是我想要的。

我可以使用通用的for_each函数作为这些类的朋友吗(例如,包含unique_ptrs向量的Organization)?

如何(在类外部)迭代vector<unique_ptr<T>>的私有成员

5 个答案:

答案 0 :(得分:3)

最简单且易读的方法是提供一种访问方法,该方法将可能const的引用返回给数据成员。这样,您就不会尝试复制不可复制的成员。

const vector<unique_ptr<Item>>& getItems()
{
    return items_;
}

可以像这样使用

for (const auto& item : organizationInstance.getItems())
    item->doStuff();

答案 1 :(得分:3)

您可以在getEmployees()中返回employee_的引用以进行迭代

const vector<unique_ptr<Employee>>& getEmployees()
{
    return employee_;
}

答案 2 :(得分:2)

您要寻找的是迭代器。 transformstd::vector::begin()将迭代器返回到向量的第一个元素和最后一个元素。然后,您可以做类似的事情。

std::vector::end()

哪里

for (auto iter = organization.get_employees_begin(); iter != organization.get_employees.end(); ++iter) {
    do_something(*iter);
}

class Organization { auto get_employees_begin() { return employees_.begin(); } auto get_employees_begin() const { return employees_.begin(); } auto get_employees_end() { return employees_.end(); } auto get_employees_end() const { return employees_.end(); } } 版本返回const迭代器,类似于指向const的指针,因为它们不允许修改向量。与返回对向量的引用相比,此方法的另一个好处是,它完全将实现与接口分离。如果您出于某种原因不在乎,可以使用它。

const

这将允许您使用所有矢量实用程序,但是如果内部容器从矢量更改为其他内容,则所有依赖它们的代码也会中断。

在任何情况下,如果不应直接修改向量,则可能不希望提供非class Organization { auto& get_employees() { return employees_; } const auto& get_employees() const { return employees_; } } 函数。

答案 3 :(得分:1)

仅允许迭代,不进行任何向量特定的操作,可以使用boost::range

auto getItems() {
    return boost::make_iterator_range(employees_.begin(), employees_.end());
}

答案 4 :(得分:1)

这是一个简单的span类。它类似于gsl::span。它表示T元素的连续缓冲区的视图(如数组中的视图):

template<class T>
struct span {
  T* begin() const { return b; }
  T* end() const { return e; }
  T* data() const { return begin(); }
  std::size_t size() const { return end()-begin(); }
  bool empty() const { return size()==0; }

  span( T* s, T* f ):b(s),e(f) {}
  span( T* s, std::size_t length ):span(s, s+length){}

  span() = default;

  template<class A>
  span( std::vector<T, A>& v ):
    span(v.data(), v.length() )
  {}
  template<class A>
  span( std::vector<std::remove_const_t<T>, A> const& v ):
    span(v.data(), v.length() )
  {}
  template<std::size_t N>
  span( T(& arr)[N] ):
    span(arr, N)
  {}
  template<std::size_t N>
  span( std::array<T, N>& arr ):
    span(arr.data(), N)
  {}
  template<std::size_t N>
  span( std::array<std::remove_const_t<T>, N> const& arr ):
    span(arr.data(), N)
  {}

private:
  T* b = 0;
  T* e = 0;
};

只需让您的getEmployees返回span<std::unique_ptr<Employee> const>

这暴露了调用者有效迭代所需的所有内容,并且仅此而已。

更简单的选择是返回一个std::vector<std::unique_ptr<Employee>> const&,但这会泄漏与getEmployee的使用者完全无关的实现细节。