Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用“分组”元素迭代向量?_C++_Range_Iteration_C++17 - Fatal编程技术网

C++ 使用“分组”元素迭代向量?

C++ 使用“分组”元素迭代向量?,c++,range,iteration,c++17,C++,Range,Iteration,C++17,以4种颜色包装在同一矢量中为例,设计的这一方面不容易改变-例如,来自第三方: std::vector rgb_colors = {1,1,1,2,2,2,3,3,3,4,4,4}; 以下方法可以起作用: for (size_t ci = 0; ci + 2 < rgb_colors.size(); ci+=3) { auto& red_component = rgb_colors[ci]; auto& green_component = rgb_colors[ci

以4种颜色包装在同一矢量中为例,设计的这一方面不容易改变-例如,来自第三方:

std::vector rgb_colors = {1,1,1,2,2,2,3,3,3,4,4,4};
以下方法可以起作用:

for (size_t ci = 0; ci + 2 < rgb_colors.size(); ci+=3) {
  auto& red_component = rgb_colors[ci];
  auto& green_component = rgb_colors[ci+1];
  auto& blue_component = rgb_colors[ci+2];
  //...
}
在真空中,这种方法是“无害的”。 然而,对于现代的c++/等,我通常会避开这种编码方法,因为它更脆弱/容易出错/冗余/等,现在更喜欢循环、迭代器等基于范围的编码

那么,解决这个问题的更具表现力或优雅的方式是什么呢

更新:
添加了一条关于“数据布局”不易更改的注释。

如注释中所述,创建一个表示颜色的结构,或者更确切地说,使用您用于图形的任何库可能附带的结构,以便您可以正确地与其交互:

struct color {
    int red, green, blue;
    // Add members as you see fit
};

std::vector rgb_colors = {color{1,1,1}, color{2,2,2}, color{3,3,3}, color{4,4,4}};
// or
// std::vector<color> rgb_colors = {{1,1,1}, {2,2,2}, {3,3,3}, {4,4,4}};

for (auto& c : rgb_colors) {
  auto& red_component = c.red;
  auto& green_component = c.green;
  auto& blue_component = c.blue;
  //...
}

这仍然与您的示例一样,要求您确保向量的长度可被3整除,以避免UB,并且元素是std::vector首先提供的连续数组的一部分,以便指针算术&c[i]具有定义良好的行为。

如注释中所述,创建一个表示颜色的结构,或者更确切地说,使用一个可能随图形库一起提供的结构,以便您可以正确地与它交互:

struct color {
    int red, green, blue;
    // Add members as you see fit
};

std::vector rgb_colors = {color{1,1,1}, color{2,2,2}, color{3,3,3}, color{4,4,4}};
// or
// std::vector<color> rgb_colors = {{1,1,1}, {2,2,2}, {3,3,3}, {4,4,4}};

for (auto& c : rgb_colors) {
  auto& red_component = c.red;
  auto& green_component = c.green;
  auto& blue_component = c.blue;
  //...
}

这仍然与您的示例一样,要求您确保向量的长度可被3整除,以避免UB,并且元素是std::vector首先提供的连续数组的一部分,以便指针算术&c[i]具有定义良好的行为。

如注释中所述,可以更好地定义输入数据以匹配其含义,这将最好地避免问题

但是,如果您出于某种原因被一个序列困住了,其中N个元素一次意味着什么,并且您需要经常使用它,下面是我如何使用boost::iterator_Adapter创建一个迭代器,该迭代器一次捕获N个元素

#include <cstddef>
#include <utility>
#include <iterator>
#include <tuple>
#include <boost/iterator/iterator_adaptor.hpp>

namespace N_elements_iterator_detail {
    template <typename T, std::size_t N>
    using ignore_N = T;

    template <typename T, typename IndSeq>
    struct repeat_type_helper;
    template <typename T, std::size_t ...Inds>
    struct repeat_type_helper<T, std::index_sequence<Inds...>>
    { using type = std::tuple<ignore_N<T, Inds>...>; };

    template <typename T, std::size_t N>
    using repeat_type = typename repeat_type_helper<T, std::make_index_sequence<N>>::type;

    template <typename IndSeq>
    struct deref_helper;

    template <std::size_t ...Inds>
    struct deref_helper<std::index_sequence<Inds...>>
    {
        template <typename RetType, typename FwdIter>
        static RetType deref(FwdIter iter) {
            FwdIter iter_array[] =
                { (static_cast<void>(Inds), iter++) ... };
            return RetType( *iter_array[Inds]... );
        }
    };
}

template <typename FwdIter,
          typename std::iterator_traits<FwdIter>::difference_type N,
          std::enable_if_t<(N>0)>* = nullptr>
class N_elements_iterator :
    public boost::iterator_adaptor<
        N_elements_iterator<FwdIter, N>, // CRTP Derived type
        FwdIter,                         // Implementation base iterator
        N_elements_iterator_detail::repeat_type<
            typename std::iterator_traits<FwdIter>::value_type, N>,
        boost::use_default,              // Iterator category
        N_elements_iterator_detail::repeat_type<
            typename std::iterator_traits<FwdIter>::reference, N>>
{
public:
    using N_elements_iterator::iterator_adaptor::iterator_adaptor;

private:
    friend class boost::iterator_core_access;

    typename N_elements_iterator::reference dereference() const {
        return N_elements_iterator_detail::deref_helper<
            std::make_index_sequence<N>>
            ::template deref<typename N_elements_iterator::reference>(
                this->base());
    }

    void advance(typename N_elements_iterator::difference_type dist) {
        std::advance(this->base_reference(), N * dist);
    }

    void increment() { advance(1); }
    void decrement() { advance(-1); }

    // N must be the same, but we can subtract for example
    // N_elements_iterator<C::iterator, N> and N_elements_iterator<C::const_iterator, N>
    template <typename OtherIter>
    auto distance_to(const N_elements_iterator<OtherIter, N>& other) const {
        return N * std::distance(this->base(), other.base());
    }
};

template <auto N, typename FwdIter>
N_elements_iterator<FwdIter, N> make_N_elements_iterator(FwdIter iter)
{ return N_elements_iterator<FwdIter, N>{ iter }; }

// -----

#include <vector>
#include <iostream>

int main() {
    std::vector rgb_colors = {1,1,1,2,2,2,3,3,3,4,4,4};

    for (auto c = make_N_elements_iterator<3>(rgb_colors.cbegin());
         c != make_N_elements_iterator<3>(rgb_colors.cend());
         ++c) {
        auto&& [red, green, blue] = *c;
        std::cout << "red " << red
                  << ", green " << green
                  << ", blue " << blue
                  << '\n';
    }
}

请参阅。

如注释中所述,可以更好地定义输入数据以匹配其含义,这将最好地避免问题

但是,如果您出于某种原因被一个序列困住了,其中N个元素一次意味着什么,并且您需要经常使用它,下面是我如何使用boost::iterator_Adapter创建一个迭代器,该迭代器一次捕获N个元素

#include <cstddef>
#include <utility>
#include <iterator>
#include <tuple>
#include <boost/iterator/iterator_adaptor.hpp>

namespace N_elements_iterator_detail {
    template <typename T, std::size_t N>
    using ignore_N = T;

    template <typename T, typename IndSeq>
    struct repeat_type_helper;
    template <typename T, std::size_t ...Inds>
    struct repeat_type_helper<T, std::index_sequence<Inds...>>
    { using type = std::tuple<ignore_N<T, Inds>...>; };

    template <typename T, std::size_t N>
    using repeat_type = typename repeat_type_helper<T, std::make_index_sequence<N>>::type;

    template <typename IndSeq>
    struct deref_helper;

    template <std::size_t ...Inds>
    struct deref_helper<std::index_sequence<Inds...>>
    {
        template <typename RetType, typename FwdIter>
        static RetType deref(FwdIter iter) {
            FwdIter iter_array[] =
                { (static_cast<void>(Inds), iter++) ... };
            return RetType( *iter_array[Inds]... );
        }
    };
}

template <typename FwdIter,
          typename std::iterator_traits<FwdIter>::difference_type N,
          std::enable_if_t<(N>0)>* = nullptr>
class N_elements_iterator :
    public boost::iterator_adaptor<
        N_elements_iterator<FwdIter, N>, // CRTP Derived type
        FwdIter,                         // Implementation base iterator
        N_elements_iterator_detail::repeat_type<
            typename std::iterator_traits<FwdIter>::value_type, N>,
        boost::use_default,              // Iterator category
        N_elements_iterator_detail::repeat_type<
            typename std::iterator_traits<FwdIter>::reference, N>>
{
public:
    using N_elements_iterator::iterator_adaptor::iterator_adaptor;

private:
    friend class boost::iterator_core_access;

    typename N_elements_iterator::reference dereference() const {
        return N_elements_iterator_detail::deref_helper<
            std::make_index_sequence<N>>
            ::template deref<typename N_elements_iterator::reference>(
                this->base());
    }

    void advance(typename N_elements_iterator::difference_type dist) {
        std::advance(this->base_reference(), N * dist);
    }

    void increment() { advance(1); }
    void decrement() { advance(-1); }

    // N must be the same, but we can subtract for example
    // N_elements_iterator<C::iterator, N> and N_elements_iterator<C::const_iterator, N>
    template <typename OtherIter>
    auto distance_to(const N_elements_iterator<OtherIter, N>& other) const {
        return N * std::distance(this->base(), other.base());
    }
};

template <auto N, typename FwdIter>
N_elements_iterator<FwdIter, N> make_N_elements_iterator(FwdIter iter)
{ return N_elements_iterator<FwdIter, N>{ iter }; }

// -----

#include <vector>
#include <iostream>

int main() {
    std::vector rgb_colors = {1,1,1,2,2,2,3,3,3,4,4,4};

    for (auto c = make_N_elements_iterator<3>(rgb_colors.cbegin());
         c != make_N_elements_iterator<3>(rgb_colors.cend());
         ++c) {
        auto&& [red, green, blue] = *c;
        std::cout << "red " << red
                  << ", green " << green
                  << ", blue " << blue
                  << '\n';
    }
}

请参阅。

struct color{int red;int green;int blue;};向量rgb_颜色={1,1,1},{2,2},{3,3,3},{4,4,4};你能描述一下,你想要实现什么吗?我相信有一种方法可以创建一个迭代器适配器来检索向量的n,n+1和n+2元素,但是你最好还是按照@NathanOliver说的做这可能是一个很好的问题,如果你把它变成完整正确的代码,但在这里,它是纯粹基于观点的结构颜色{int-red;int-green;int-blue;};向量rgb_颜色={1,1,1},{2,2},{3,3,3},{4,4,4};你能描述一下,你想要实现什么吗?我相信有一种方法可以创建一个迭代器适配器来检索向量的n,n+1和n+2元素,但是你最好还是按照@NathanOliver说的做这可能是一个很好的问题,如果你把它变成完整正确的代码,但是这里的想法纯粹是正确的,但是用C++做这些事情是没有用的。如果是Windows,定义颜色和alpha的结构已经存在并建立。如果使用诸如OpenCV之类的库,则存在结构。在C++级上做它只是无UnC++,它本身没有GUI库,因此缺少任何这样定义的结构。这是C++ 20还是已经用C++ 17好?我的意思是:STD::向量RBGHORIZE =……@ ICDECV463035818 CTAD,在C++中引入17@NathanOliver天哪,我落后太多了。对于日常工作,我仍然必须使用C++11://@MichaelChourdakis是的,当然,应该使用库给定的类型,以便它能够正确地与它交互。我已经给答案加了一个注释。答案是正确的,但是用普通C++做这些事情是没有用的。如果是Windows,定义颜色和alpha的结构已经存在并建立。如果使用诸如OpenCV之类的库,则存在结构。在C++级上做它只是无UnC++,它本身没有GUI库,因此缺少任何这样定义的结构。这是C++ 20还是已经用C++ 17好?我的意思是:STD::向量RBGHORIZE =……@ ICDECV463035818 CTAD,在C++中引入17@NathanOliver天哪,我落后太多了。对于日常工作,我仍然必须使用C++11://@MichaelChourdakis是的,当然,应该使用库给定的类型,以便它能够正确地与它交互。我在回答中添加了一条评论。