簡體   English   中英

如何基於“索引”跳過基於范圍的 for 循環中的元素?

[英]How can I skip elements in a range-based for loop based on 'index'?

有沒有辦法在基於 C++11 范圍的 for 循環中訪問迭代器(我想沒有循環索引?)?

通常我們需要對容器的第一個元素做一些特殊的事情,並迭代剩余的元素。 所以我在這個偽代碼中尋找類似c++11_get_index_of語句的東西:

for (auto& elem: container) 
{
  if (c++11_get_index_of(elem) == 0)
     continue;

  // do something with remaining elements
}

在那種情況下,我真的很想避免回到舊式手動迭代器處理代碼。

通常我們需要對容器的第一個元素做一些特殊的事情,並迭代剩余的元素。

我很驚訝地看到到目前為止沒有人提出這個解決方案:

  auto it = std::begin(container);

  // do your special stuff here with the first element

  ++it;

  for (auto end=std::end(container); it!=end; ++it) {

      // Note that there is no branch inside the loop!

      // iterate over the rest of the container
  }

它的一大優點是分支被移出循環。 它使循環更簡單,也許編譯器也可以更好地優化它。

如果您堅持使用基於范圍的 for 循環,那么最簡單的方法可能是這樣(還有其他更丑陋的方法):

std::size_t index = 0;

for (auto& elem : container) {

  // skip the first element
  if (index++ == 0) {
     continue;
  }

  // iterate over the rest of the container
}

但是,如果您只需要跳過第一個元素,我會認真地將分支移出循環。

Boost 提供了一種簡潔的方式來做到這一點:

std::vector<int> xs{ 1, 2, 3, 4, 5 };
for (const auto &x : boost::make_iterator_range(xs.begin() + 1, xs.end())) {
  std::cout << x << " ";
}
// Prints: 2 3 4 5

您可以在boost/range/iterator_range.hpp頭文件中找到make_iterator_range

不,您無法在基於范圍的for循環中獲取迭代器(當然,無需查找容器中的元素)。 迭代器由標准定義為名為__begin但這僅用於說明。 如果您需要迭代器,則打算使用普通的for循環。 基於范圍的for循環存在的原因是那些您不需要自己處理迭代的情況。

使用autostd::beginstd::end ,您的for循環應該仍然非常簡單:

for (auto it = std::begin(container); it != std::end(container); it++)

如何在迭代中使用簡單的 for 循環:

for(auto it = container.begin(); it != container.end(); it++)
{
    if(it == container.begin())
    {
        //do stuff for first
    }
    else
    {
        //do default stuff
    }
}

它不是基於范圍的,但它是功能性的。 如果您可能仍想使用范圍循環:

int counter = 0;
for(auto &data: container)
{
    if(counter == 0)
    {
        //do stuff for first
    }
    else
    {
        //do default stuff
    }
    counter++;
}

在迭代元素時,總是更喜歡使用algorithm ,並且只有在沒有任何算法適合時才使用普通的for循環。

選擇正確的算法取決於您想對元素做什么……您還沒有告訴我們。

如果要跳過第一個元素,請轉儲示例:

if (!container.empty()) {
   for_each(++container.begin(), container.end(), [](int val) { cout << val; });
}

如果沒有迭代器、指針或侵入性索引,就無法知道元素在容器內的距離。 這是一個簡單的方法:

int index= 0;
for (auto& elem: container) 
{
  if (index++ == something)
     continue;

  // do something with remaining elements
}

如果要跳過第一個元素,另一種方法是使用 std::deque 和 pop_front 第一個元素。 然后你可以像往常一樣用容器做你的 ranged for 循環。

當我需要在隨機訪問容器上做這樣的事情時,我的習慣是遍歷索引。

for( std::size_t i : indexes( container ) ) {
  if (i==0) continue;
  auto&& e = container[i];
  // code
}

唯一棘手的部分是編寫indexes ,它返回 boost 調用counting迭代器的范圍。 從迭代器創建一個基本的可迭代范圍很容易:要么使用 boost 的范圍概念,要么滾動你自己的。

任意迭代器類型的基本范圍是:

template<typename Iterator>
struct Range {
  Iterator b; Iterator e;
  Range( Iterator b_, Iterator e_ ):b(b_), e(e_) {};
  Iterator begin() const { return b; }
  Iterator end() const { return e; }
};

你可以把它弄得一團糟,但這是核心。

我會盡量避免使用迭代器,因為基於范圍的 for 循環的想法是擺脫它們。 C++20 開始,要跳過container的第一個元素,我將采用以下方法之一。 為了完整起見,我還包括如何單獨處理第一個元素:

  1. 處理循環外的第一個元素

    您可以使用所有 序列容器都存在的container.front()來訪問第一個元素。 但是,您必須確保容器不為空以避免分段錯誤。 然后,要跳過循環中的第一個(或更多)元素,您可以使用Ranges library 中的范圍適配器std::views::drop 總而言之,它看起來如下:

     std::vector<int> container { 1, 2, 3 }; if(!container.empty()) { // do something with first element std::cout << "First element: " << container.front() << std::endl; } for (auto& elem : container | std::views::drop(1)) { // do something with remaining elements std::cout << "Remaining element: " << elem << std::endl; }

    除了container.front()您還可以將另一個基於范圍的 for 循環與范圍適配器std::views::take(1) take()drop()的優點是即使它們的參數超過container中元素的數量,它們也能安全地工作。

  2. 處理循環內的第一個元素

    您可以在基於范圍的 for 循環中使用init 語句來定義布爾標志(甚至計數器)。 這樣,標志僅在循環范圍內可見。 您可以在循環內使用該標志,如下所示:

     std::vector<int> container { 1, 2, 3 }; for(bool isFirst(true); auto& elem : container) { if(isFirst) { // do something with first element std::cout << "First element: " << elem << std::endl; isFirst = false; continue; } // do something with remaining elements std::cout << "Remaining element: " << elem << std::endl; }

顯示兩種方法的輸出:

第一個元素:1
剩余元素:2
剩余元素:3

Wandbox 上的代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM