returning iterators to boost adaptor

I would like to offer to users of a class the possibility to iterate over a member container, but with a transform applied to the elements. Boost adaptors seem to be a good fit for transforming a container, but I do not know how could I possibly apply it to my use case.

The function returns an IterPair template wrapping the begin and end iterators and it works without the transform. However, with the transform I am returning a pair of iterators of a local variable. Making the transformed container a member is not possible since it does not have a default constructor.

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_;
}

I think you may be approaching this incorrectly... instead of doing what you wrote, I would offer the following approach, which is really too much code to flesh-out in a quick post:

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()); }
};

I'm sorry for barely sketching out the bones of this, but it turns out to be considerably more code than I wish to compile and test right now...

The idea being that you create a wrapper container class that contains an iterator proxy to the underlying container as well as a reference (pointer) to the underlying container. When the proxy iterator is dereferenced, using it's operator*, it applies a transform to the underlying container element and returns its result.

Where this falls short, is that it breaks the STL's API for certain operations, just as std::vector<bool> breaks things - you can't assign elements back into the container from a proxy_iterator handle without some more hackery and a guarantee that you can reverse-map the result-type of your transfer back into your original data domain (ie your transform is 1 to 1, or bijective). As a result of this, certain operations, like std::sort will fail on your proxy container, but it certainly is a good option for data transform if you need to have a const container to move data between two different api's.


I would just return the range and leave it up to the user to call begin/end (or use range for as in the example below) on that:

#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

链接地址: http://www.djcxy.com/p/47362.html

上一篇: 将包含指针的结构复制到CUDA设备

下一篇: 返回迭代器来提升适配器