簡體   English   中英

基於范圍的for循環用於私有映射值

[英]range-based for loop for private map values

我有以下代碼:

#include "stdafx.h"
#include <map>
#include <string>
#include <iostream>

class MyObject
{
public:
    MyObject()
        : m_Items{ { 1, "one" },{ 2, "two" },{ 3, "three" } }
    {}

    RETURNTYPE GetStringIterator() const
    {
        IMPLEMENTATION
    }

private:
    std::map<int, std::string> m_Items;
};


int main()
{
    MyObject o;
    for (auto& s : o.GetStringIterator())
    {
        std::cout << s;
    }
}

RETURNTYPEIMPLEMENTATION應該允許MyObject任何客戶端(在本例中為main()函數)迭代m_Items映射的值,而不復制任何數據? 似乎這應該可以使用基於c ++ 11范圍的循環和迭代器。 但我無法弄清楚如何。

基於范圍的迭代可以像這樣實現:

class MyObject
{
public:
    MyObject()
        : m_Items{ { 1, "one" },{ 2, "two" },{ 3, "three" } }
    {}

    auto begin()       { return m_Items.begin(); }
    auto begin() const { return m_Items.begin(); }
    auto end()       { return m_Items.end(); }
    auto end() const { return m_Items.end(); }

private:
    std::map<int, std::string> m_Items;
};

復制或不復制值取決於代碼在調用站點的寫入方式:

MyObject a;
for(auto [key,value] : a) {} // copies are made
for(auto & [key,value] : a) {} // no copy
for(auto const & [key,value] : a) {} // no copy

您可以通過刪除beginend的非const版本來禁用地圖值的修改:

class MyObject
{
public:
    MyObject()
        : m_Items{ { 1, "one" },{ 2, "two" },{ 3, "three" } }
    {}

    auto begin() const { return m_Items.begin(); }
    auto end() const { return m_Items.end(); }

private:
    std::map<int, std::string> m_Items;
};

然后,嘗試修改范圍for for循環中的值將導致編譯錯誤:

MyObject a;
for(auto & [key,value] : a) {
    //value.push_back('a');      // Not OK 
}
for(auto & [key,value] : a) {
    cout << value;             // OK
}

請注意,如果地圖是實現細節,則應使用@Barry提出的答案,因為它僅迭代地圖的值,而不是關鍵字。

你可以使用boost::adaptors::map_values ,它適用於C ++ 11:

auto GetStringIterator() const
    // NB: have the move the declaration of m_Items ahead of this function for this to work
    -> decltype(m_Items | boost::adaptors::map_values)
{
    return m_Items | boost::adaptors::map_values;
}

或者它的range-v3等價, view::values 兩者都可以像values(m)而不是m | values m | values ,如果你喜歡那樣的話。

兩種解決方案都會將視圖返回到地圖的值。 這是一個不擁有任何底層元素的對象,復制起來很便宜 - 即O(1)。 我們不是在對地圖或其任何底層元素進行編碼。

您可以使用它,就好像它是任何其他范圍:

for (std::string const& s : o.GetStringIterator()) {
    // ...
}

此循環不會復制任何字符串。 每個s直接指向map存儲的相應string

我將在首先回答這個問題。

這是一個最小的映射iteratoroid:

template<class F, class It>
struct iterator_mapped {
  decltype(auto) operator*() const {
    return f(*it);
  }

  iterator_mapped( F f_in, It it_in ):
    f(std::move(f_in)),
    it(std::move(it_in))
  {}

  iterator_mapped( iterator_mapped const& ) = default;
  iterator_mapped( iterator_mapped && ) = default;
  iterator_mapped& operator=( iterator_mapped const& ) = default;
  iterator_mapped& operator=( iterator_mapped && ) = default;

  iterator_mapped& operator++() {
    ++it;
    return *this;
  }
  iterator_mapped operator++(int) {
    auto copy = *this;
    ++*this;
    return copy;
  }
  friend bool operator==( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
    return lhs.it == rhs.it;
  }
  friend bool operator!=( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
    return !(lhs==rhs);
  }
private:
  F f;
  It it;
};

它在技術上不是一個迭代器,但它有資格for(:)循環。

template<class It>
struct range_t {
  It b, e;
  It begin() const { return b; }
  It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
  return {std::move(b), std::move(e)};
}

以上是一個絕對最小的迭代器范圍類型,可以for(:)迭代。

template<class F, class R>
auto map_range( F&& f, R& r ) {
  using std::begin; using std::end;
  auto b = begin(r);
  auto e = end(r);
  using it = iterator_mapped<std::decay_t<F>, decltype(b)>;
  return range( it( f, b ), it( f, e ) );
}

請注意R& not R&& ; 在這里采取r值是危險的。

auto GetStringIterator() const
{
  return map_range( [](auto&& pair)->decltype(auto){
    return pair.second;
  }, m_Items );
}

並做了。

將其轉換為是一件痛苦的事。 你必須用std::function s來代替lambdas(或編寫執行任務而不是lambda的函數對象),用auto和尾隨返回類型替換decltype(auto) ,給lambdas提供auto&&參數的確切類型等等,你最終會得到大約25%-50%的代碼,其中大部分都是模糊的類型追逐。

這基本上是boost::adaptors::map_values作用,但是這是手動滾動的,這樣你就可以理解它是如何工作的,並且沒有boost依賴。

暫無
暫無

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

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