C++ 迭代对象 vector 并将 STL 算法应用于成员变量

标签 c++ stl iterator

迭代自定义对象 vector 但仅访问单个成员以应用通用 STL 算法的快速方法是什么?

struct Foo
{
    std::string a;
    double b = 1.0;
};

int main()
{
    std::vector<Foo> fooVector(20);

    // iterate over all members b -- as if we were iterating over a std::vector<double>
    std::discrete_distribution<int> dist(/*??*/, /*??*/);
}

我的意思是“快”

  • 没有自定义迭代器——或者只有一个非常轻量级的迭代器(——几行代码,没有 boost iterator_facade 等),
  • 不修改取消引用运算符(--没那么快)。

最佳答案

std::discrete_distribution<...> 的构造函数不支持任何显式投影值的方式(如函数对象可选地应用于在使用前转换 *it 的结果)。因此,我认为存在三种基本方法:

  1. 使用中间体 std::vector<double>获取其迭代器产生 double 值的范围:

    std::vector<double> tmp; // reserve() as desired
    std::transform(fooVector.begin(), fooVector.end(),
                   std::back_inserter(tmp),
                   [](Foo const& f){ return f.b; });
    std::discrete_distribution<int> d(tmp.begin(), tmp.end());
    
  2. Foo 上使用转换运算符可能是可行的转换成 double :

    class Foo {
        // ...
        operator double() const { return this->b; }
    };
    // ...
    std::discrete_distribution<int> d(fooVector.begin(), fooVector.end());
    
  3. 为迭代器创建一个包装器并使用它。它不需要任何花哨的东西,但将一个简单的输入迭代器放在一起仍然比较复杂:

    template <typename InIt>
    class project_iterator {
        InIt it;
    public:
        explicit project_iterator(InIt it): it(it) {}
        double operator*() const { return *this->it; }
        project_iterator& operator++() { ++this->it; return *this; }
        project_iterator  operator++(int) {
            project_iterator rc(*this);
            this->operator++();
            return *this;
        }
        bool operator==(project_iterator const& other) const {
            return this->it == other.it;
        }
        bool operator!=(project_iterator const& other) const {
            return !(*this == other);
        }
    };
    template <typename It>
    project_iterator<It> project(It it) {
        return project_iterator<It>(it);
    }
    namespace std {
        template <typename It>
        class iterator_traits<project_iterator<It> {
        public:
            typedef typename std::iterator_traits<It>::difference_type difference_type;
            typedef double value_type;
            typedef double& reference;
            typedef double* pointer;
            typedef std::input_iterator_tag iterator_category;
        }
    }
    // ...
    std::discrete_distribution<int> d(project(fooVector.begin()), project(fooVector.end());
    

显然,这些方法有多种变体,但我认为没有其他方法可以巧妙地完成。本质上缺少的是对序列进行投影的一般方法(我通常将它们称为 property maps )。

关于C++ 迭代对象 vector 并将 STL 算法应用于成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34198818/

相关文章:

c++ - 如果 X 是某个有序容器 S 的迭代器 S.begin(),则 prev(X) 是什么,例如S是集合?

c++ - Makefile 不检查头文件中的更新

c++ - OpenGL 渲染错误

c++ - STL map 排序

c++ - 轮类作业

c++ - 关于模板中随机访问迭代器的运算符+重载的问题

c++ - dyld : Library not loaded:/usr/local/opt/jpeg/lib/libjpeg. 9.dylib OpenCV C++ MacOS

python - 使用 Python 包装的 C++ 类进行并行计算 : performing operations in every element of a vector

c++ - 我在一些指针上遇到了问题,调试结束时访问位置失败

c++ - 如何在字符串替换后获得有效的迭代器