【问题标题】:returning iterators to boost adaptor-transformed container返回迭代器以提升适配器转换的容器
【发布时间】:2017-12-12 21:31:10
【问题描述】:

我想为类的用户提供迭代成员容器的可能性,但对元素应用了转换。 Boost 适配器似乎非常适合转换容器,但我不知道如何将它应用到我的用例中。

该函数返回一个包装了开始和结束迭代器的 IterPair 模板,它无需转换即可工作。但是,通过转换,我返回了一对局部变量的迭代器。 使转换后的容器成为成员是不可能的,因为它没有默认构造函数。

class A
{
public:
    IterPair get_elems()
    {
          auto tr_vect =  vect_ | boost::adaptors::transformed(std::mem_fn(&std::string::c_str));
          return {std::begin(tr_vect), std::end(tr_vect)};
    }
private:
    std::vector<std::string> vect_;
}

【问题讨论】:

    标签: c++ c++11 boost


    【解决方案1】:

    我认为您可能错误地处理了这个问题...与其按照您写的那样做,我会提供以下方法,这确实是太多代码,无法在快速帖子中充实:

    template <typename CONTAINER, // your underlying container
              typename TRANSFORM> // functor for your transform
    class transform_adaptor
    {
        template <typename IT = typename CONTAINER::iterator>
        class proxy_iterator : private TRANSFORM {
            // standard iterator typedefs, sourced from CONTAINER::iterator
    
            typedef IT underlying_iterator;
            underlying_iterator i;
         public:
            auto operator * () const -> decltype(TRANSFORM{}(*i))
            {
                return this->operator () (*i);
            }
            // Other proxy functions for the underlying iterator,
            // i.e. operator++, etc
        }
    
        CONTAINER * cptr;
     public:
        typedef proxy_iterator iterator;
        typedef proxy_iterator const_iterator;
        // necessary value_type, iterator, allocator, etc adaptors here
    
        iterator begin() { return proxy_iterator(cptr->begin()); }
        iterator end() { return proxy_iterator(cptr->end()); }
    };
    

    很抱歉,我几乎没有勾勒出这个框架,但事实证明它的代码比我现在希望编译和测试的要多得多......

    这个想法是您创建一个包装容器类,其中包含一个指向底层容器的迭代器代理以及一个指向底层容器的引用(指针)。当代理迭代器被取消引用时,使用它的 operator*,它将转换应用于底层容器元素并返回其结果。

    不足之处在于,它破坏了 STL 的某些操作的 API,就像 std::vector&lt;bool&gt; 破坏了一些东西一样 - 如果没有更多的骇客和保证,你不能从 proxy_iterator 句柄将元素分配回容器中可以将传输的结果类型反向映射回原始数据域(即您的转换是 1 到 1,或双射)。因此,某些操作(例如 std::sort )在您的代理容器上会失败,但如果您需要一个 const 容器在两个不同的 api 之间移动数据,它肯定是数据转换的好选择。

    【讨论】:

      【解决方案2】:

      我将只返回范围,并留给用户调用 begin/end(或使用范围,如下例所示):

      #include <boost/range/adaptor/transformed.hpp>
      
      #include <cstring>
      #include <initializer_list>
      #include <iostream>
      #include <string>
      #include <vector>
      
      class A {
      public:
          A(std::initializer_list<std::string> xs) : vect_{std::move(xs)} {}
      
          // auto return type requires c++14
          auto get_elems() const {
              return vect_ |
                     boost::adaptors::transformed(std::mem_fn(&std::string::c_str));
          }
      
      private:
          std::vector<std::string> vect_;
      };
      
      int main(int argc, char** argv) {
          A a{"a", "ab", "abc"};
          auto xs = a.get_elems();
          for (const auto& x : xs) {
              std::cout << std::strlen(x) << "\n";
          }
          return 0;
      }
      

      live example

      【讨论】:

        猜你喜欢
        • 2015-02-18
        • 1970-01-01
        • 2021-12-09
        • 2013-05-14
        • 2012-11-18
        • 2017-06-01
        • 2017-10-30
        • 1970-01-01
        • 2016-08-17
        相关资源
        最近更新 更多