簡體   English   中英

使用boost :: join合並多個數組

[英]merging multiple arrays using boost::join

使用boost :: join訪問和更改不同數組的值是更好的主意嗎?

我已經在class element定義了一個成員數組。

class element
{
public:
     element();
     int* get_arr();
private:
     int m_arr[4];   

}

在不同的地方,我正在訪問這些數組,並使用boost :: join並更改了數組值將它們連接在一起。

 //std::vector<element> elem;
 auto temp1 = boost::join(elem[0].get_arr(),elem[1].get_arr());
 auto joined_arr = boost::join(temp1,elem[2].get_arr()); 

//now going to change the values of the sub array
for(auto& it:joined_arr)
{
     it+=  sample[i];
      i++;
}

修改上述類中array的值是一個好主意嗎?

在您的代碼中,您可能想加入4個元素的數組。 為此,將get_arr的簽名get_arr為:

typedef int array[4];
array& get_arr() { return m_arr; }

這樣數組的大小就不會丟失。

在性能方面,通過聯接視圖訪問元素的成本為非零。 double for循環將是最有效的,並且也易於閱讀,例如:

for(auto& e : elem)
    for(auto& a : e.get_arr())
        a += sample[i++];

boost::join在每個合成步驟都返回一個更復雜的類型。 在某些時候,您可能會超出編譯器的內聯限制,這樣您將產生運行時成本¹。

跳出框框思考,實際上看起來您正在創建一個緩沖區抽象,使您可以像IO那樣進行分散/聚集,分配很少。

碰巧的是,Boost Asio為此提供了很好的抽象²,您可以使用它: http : //www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/MutableBufferSequence.html

正如我在此答案代碼較早版本中發現的那樣 ,可悲的是,抽象僅適用於通過本機char型元素訪問的緩沖區。 那不好

因此,在此重寫中,我提供了一個類似的抽象,它只包含一個知道如何迭代一系列“緩沖區”的“分層迭代器”(在此實現中,任何范圍都可以)。

您可以選擇直接對一系列范圍進行操作,例如:

std::vector<element> seq(3); // tie 3 elements together as buffer sequence
element& b = seq[1];

或者,不作任何進一步更改,通過引用:

element a, b, c;
std::vector<std::reference_wrapper<element> > seq {a,b,c}; // tie 3 elements together as buffer sequence

在底部呈現的C ++版本演示了這種做法住在Coliru

迭代器實現

我使用了Boost Range和Boost Iterator:

template <typename Seq,
         typename WR = typename Seq::value_type,
         typename R = typename detail::unwrap<WR>::type,
         typename V = typename boost::range_value<R>::type
     >
struct sequence_iterator : boost::iterator_facade<sequence_iterator<Seq,WR,R,V>, V, boost::forward_traversal_tag> {
    using OuterIt = typename boost::range_iterator<Seq>::type;
    using InnerIt = typename boost::range_iterator<R>::type;

    // state
    Seq& _seq;
    OuterIt _ocur, _oend;
    InnerIt _icur, _iend;

    static sequence_iterator begin(Seq& seq) { return {seq, boost::begin(seq), boost::end(seq)}; }
    static sequence_iterator end(Seq&   seq) { return {seq, boost::end(seq),   boost::end(seq)}; }

    // the 3 facade operations
    bool equal(sequence_iterator const& rhs) const {
        return ((_ocur==_oend) && (rhs._ocur==rhs._oend))
            || (std::addressof(_seq) == std::addressof(rhs._seq) &&
                _ocur == rhs._ocur && _oend == rhs._oend &&
                _icur == rhs._icur && _iend == rhs._iend);
    }

    void increment() {
        if (++_icur == _iend) {
            ++_ocur;
            setup();
        }
    }

    V& dereference() const {
        assert(_ocur != _oend);
        assert(_icur != _iend);
        return *_icur;
    }

  private:
    void setup() { // to be called after entering a new sub-range in the sequence
        while (_ocur != _oend) {
            _icur = boost::begin(detail::get(*_ocur));
            _iend = boost::end(detail::get(*_ocur));

            if (_icur != _iend)
                break;
            ++_ocur; // skid over, this enables simple increment() logic
        }
    }

    sequence_iterator(Seq& seq, OuterIt cur, OuterIt end)
        : _seq(seq), _ocur(cur), _oend(end) { setup(); }
};

基本上與boost::asio::buffers_iterator具有相同的迭代器,但是它不假定元素類型。 現在,為任何范圍的序列創建sequence_iterator非常簡單:

template <typename Seq> auto buffers_begin(Seq& seq) { return sequence_iterator<Seq>::begin(seq); }
template <typename Seq> auto buffers_end(Seq& seq)   { return sequence_iterator<Seq>::end(seq); }

實施您的測試程序

生活在Coliru

// DEMO
struct element {
    int peek_first() const { return m_arr[0]; }

    auto begin() const { return std::begin(m_arr); } 
    auto end() const   { return std::end(m_arr);   } 
    auto begin()       { return std::begin(m_arr); } 
    auto end()         { return std::end(m_arr);   } 

  private:
    int m_arr[4] { };
};

namespace boost { // range adapt
    template <> struct range_iterator<element> { using type = int*; };
    // not used, but for completeness:
    template <> struct range_iterator<element const> { using type = int const*; };
    template <> struct range_const_iterator<element> : range_iterator<element const> {};
}

#include <algorithm>
#include <iostream>
#include <vector>

template <typename Output, typename Input, typename Operation>
size_t process(Output& output, Input const& input, Operation op) {
    auto ib = boost::begin(input), ie = boost::end(input);
    auto ob = boost::begin(output), oe = boost::end(output);

    size_t n = 0;
    for (;ib!=ie && ob!=oe; ++n) {
        op(*ob++, *ib++);
    }
    return n;
}

int main() {
    element a, b, c;
    std::vector<std::reference_wrapper<element> > seq {a,b,c}; // tie 3 elements together as buffer sequence

    //// Also supported, container of range objects directly:
    // std::list<element> seq(3); // tie 3 elements together as buffer sequence
    // element& b = seq[1];

    std::vector<int> const samples { 
         1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32
    };

    using boost::make_iterator_range;
    auto input  = make_iterator_range(samples);
    auto output = make_iterator_range(buffers_begin(seq), buffers_end(seq));

    while (auto n = process(output, input, [](int& el, int sample) { el += sample; })) {
        std::cout << "Copied " << n << " samples, b starts with " << b.peek_first() << "\n";
        input.advance_begin(n);
    }
}

打印

Copied 12 samples, b starts with 5
Copied 12 samples, b starts with 22
Copied 8 samples, b starts with 51

完整列表,與C ++ 11兼容

生活在Coliru

#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
#include <functional> // std::reference_wrapper

namespace detail {
    template<typename T> constexpr T&       get(T &t)                         { return t;  } 
    template<typename T> constexpr T const& get(T const &t)                   { return t;  } 
    template<typename T> constexpr T&       get(std::reference_wrapper<T> rt) { return rt; } 

    template <typename T> struct unwrap { using type = T; };
    template <typename T> struct unwrap<std::reference_wrapper<T> > { using type = T; };
}

template <typename Seq,
         typename WR = typename Seq::value_type,
         typename R = typename detail::unwrap<WR>::type,
         typename V = typename boost::range_value<R>::type
     >
struct sequence_iterator : boost::iterator_facade<sequence_iterator<Seq,WR,R,V>, V, boost::forward_traversal_tag> {
    using OuterIt = typename boost::range_iterator<Seq>::type;
    using InnerIt = typename boost::range_iterator<R>::type;

    // state
    Seq& _seq;
    OuterIt _ocur, _oend;
    InnerIt _icur, _iend;

    static sequence_iterator begin(Seq& seq) { return {seq, boost::begin(seq), boost::end(seq)}; }
    static sequence_iterator end(Seq&   seq) { return {seq, boost::end(seq),   boost::end(seq)}; }

    // the 3 facade operations
    bool equal(sequence_iterator const& rhs) const {
        return ((_ocur==_oend) && (rhs._ocur==rhs._oend))
            || (std::addressof(_seq) == std::addressof(rhs._seq) &&
                _ocur == rhs._ocur && _oend == rhs._oend &&
                _icur == rhs._icur && _iend == rhs._iend);
    }

    void increment() {
        if (++_icur == _iend) {
            ++_ocur;
            setup();
        }
    }

    V& dereference() const {
        assert(_ocur != _oend);
        assert(_icur != _iend);
        return *_icur;
    }

  private:
    void setup() { // to be called after entering a new sub-range in the sequence
        while (_ocur != _oend) {
            _icur = boost::begin(detail::get(*_ocur));
            _iend = boost::end(detail::get(*_ocur));

            if (_icur != _iend)
                break;
            ++_ocur; // skid over, this enables simple increment() logic
        }
    }

    sequence_iterator(Seq& seq, OuterIt cur, OuterIt end)
        : _seq(seq), _ocur(cur), _oend(end) { setup(); }
};

template <typename Seq> auto buffers_begin(Seq& seq) { return sequence_iterator<Seq>::begin(seq); }
template <typename Seq> auto buffers_end(Seq& seq)   { return sequence_iterator<Seq>::end(seq); }

// DEMO
struct element {
    int peek_first() const { return m_arr[0]; }

    auto begin() const { return std::begin(m_arr); } 
    auto end() const   { return std::end(m_arr);   } 
    auto begin()       { return std::begin(m_arr); } 
    auto end()         { return std::end(m_arr);   } 

  private:
    int m_arr[4] { };
};

namespace boost { // range adapt
    template <> struct range_iterator<element> { using type = int*; };
    // not used, but for completeness:
    template <> struct range_iterator<element const> { using type = int const*; };
    template <> struct range_const_iterator<element> : range_iterator<element const> {};
}

#include <algorithm>
#include <iostream>
#include <vector>

template <typename Output, typename Input, typename Operation>
size_t process(Output& output, Input const& input, Operation op) {
    auto ib = boost::begin(input), ie = boost::end(input);
    auto ob = boost::begin(output), oe = boost::end(output);

    size_t n = 0;
    for (;ib!=ie && ob!=oe; ++n) {
        op(*ob++, *ib++);
    }
    return n;
}

int main() {
    element a, b, c;
    std::vector<std::reference_wrapper<element> > seq {a,b,c}; // tie 3 elements together as buffer sequence

    //// Also supported, container of range objects directly:
    // std::list<element> seq(3); // tie 3 elements together as buffer sequence
    // element& b = seq[1];

    std::vector<int> const samples { 
         1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32
    };

    using boost::make_iterator_range;
    auto input  = make_iterator_range(samples);
    auto output = make_iterator_range(buffers_begin(seq), buffers_end(seq));

    while (auto n = process(output, input, [](int& el, int sample) { el += sample; })) {
        std::cout << "Copied " << n << " samples, b starts with " << b.peek_first() << "\n";
        input.advance_begin(n);
    }
}

¹當復雜的范圍組成包含臨時變量的引用時,我會忽略auto x = complicated_range_composition complex_range_composition模式的編譯時成本和潛伏的危險:這是UB錯誤的常見來源

²已被Boost Beast,Boost Process等其他各種庫采用,並且似乎已進入C ++ 20的Networking TS中: 標頭<experimental/buffer>提要(PDF)

暫無
暫無

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

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