使用基于范围的for循环遍历除最后一个元素以外的所有元素

时间:2019-09-30 20:09:41

标签: c++ loops

对于初学者来说,我要实现的目标的简短摘要:

std::vector<std::string> v{ "one", "two", "three", "four" };
for (const std::string& str : drop_last(v)) {
   cout << str << ' ';
}

上面的代码应打印:“一二三”。

为了实现这一点,我实现了以下结构:

template <typename Container>
struct drop_last {
   using const_iterator = typename Container::const_iterator;

   explicit drop_last(const Container& container_) : m_container(container_) {}

   const_iterator begin() {
      return m_container.begin();
   }

   const_iterator end() {
      return m_container.empty() ? m_container.end() : std::prev(m_container.end());
   }
private:
   const Container& m_container;
};

除了使用临时对象时,此代码工作正常(在这种情况下,断言“无法取消引用值初始化的映射/设置迭代器”):

std::vector<int> return_temporary_vector() {
   vector<int> v;
   // ...
   return v;
}

int main(int argc_, char* argv_[]) {
   for (int value : drop_last(return_temporary_vector())) {
      // ...
   }
   // ...
}

如何调整drop_last的结构,以便满足以下条件:

  • 正确处理临时对象
  • 尽可能避免不必要的复制。也就是说,用const Container& m_container;代替Container m_container;是不合适的。

1 个答案:

答案 0 :(得分:2)

如果您将模板函数与转发参考一起使用,则可以使用该模板函数将ContainerContainer&传递给您的课程。

#include <vector>
#include <iostream>
#include <type_traits>

template <typename Container>
struct drop_last_impl {
   using const_iterator = typename std::remove_reference_t<Container>::const_iterator;

   explicit drop_last_impl(Container&& container_) : m_container(std::forward<Container>(container_)) {}

   const_iterator begin() {
      return m_container.begin();
   }

   const_iterator end() {
      return m_container.empty() ? m_container.end() : std::prev(m_container.end());
   }
private:
   const Container m_container;
};

template <typename Container>
auto drop_last(Container&& container) {
    return drop_last_impl<Container>(std::forward<Container>(container));
}

std::vector<int> return_temporary_vector() {
   std::vector<int> v{1,2,3};
   // ...
   return v;
}

int main() {
   for (int value : drop_last(return_temporary_vector())) {
      std::cout << value << std::endl;
   }
   std::vector<int> v{1,2,3};
    for (int value : drop_last(v)) {
      std::cout << value << std::endl;
   }
   // ...
}
现在,

drop_last_impl如果传递了右值,则移至std::vector<int>;如果传递了左值,则将初始化std::vector<int>&。 需要std::remove_reference_t,因为如果用std::vector<int>&实例化,我们将找不到const_iterator