为STL算法(例如std::execution::par
)指定std::for_each
执行策略时,如何使用迭代器?
在下面的示例中,我希望采用Eigen3矩阵对角线的平方根:
template<typename T>
using Matrix = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
template<typename T>
std::vector<T> getStdDev(const Matrix &x) const {
const size_t len = x.rows();
std::vector<T> stdDev(len);
// Generate indices.
size_t idx = 0;
std::vector<size_t> indices(len);
auto ind = [&idx]() {
return idx++;
};
std::generate(indices.begin(), indices.end(), ind);
// Take square root of diagonal elements.
auto sr = [&x](size_t i) {
stdDev[i] = std::sqrt(x(i, i));
};
std::for_each(std::execution::par, indices.begin(), indices.end(), sr);
return stdDev;
}
据我所知,以上代码是线程安全的。但是,如何在没有首先生成所需索引的情况下,以线程安全的方式使用Iterator达到相同的效果?假定要迭代的容器没有实现Iterator,或者没有线程安全的Iterator。
理想情况下,我希望以一般方式进行此操作(我知道Eigen具有Iterators,此处仅出于示例目的使用它)。
另外,最好只使用C++功能(不使用库,但使用任何非草稿标准)。
最佳答案
您可以使用 boost::counting_iterator
或 ranges::view::iota
之类的东西
template<typename T>
std::vector<T> getStdDev(const Matrix &x) const {
const size_t len = x.rows();
std::vector<T> stdDev(len);
// Take square root of diagonal elements.
auto sr = [&x](size_t i) {
return std::sqrt(x(i, i));
};
std::transform(std::execution::par, boost::counting_iterator<int>(0), boost::counting_iterator<int>(len), stdDev.begin(), sr);
return stdDev;
}
自己实现
counting_iterator
并不难,指定RandomAccessIterator的所有必需成员只是一件繁琐的事情。class counting_iterator
{
public:
typedef size_t value_type;
typedef const size_t& reference;
typedef const size_t* pointer;
typedef ptrdiff_t difference_type;
typedef random_access_iterator_tag iterator_category;
explicit counting_iterator(size_t x);
size_t const& base() const { return m_inc; }
reference operator*() const { return m_inc; }
counting_iterator& operator++() { ++m_inc; return *this; }
counting_iterator& operator--() { --m_inc; return *this; }
counting_iterator& operator+=(size_t i) { m_inc += i; return *this; }
counting_iterator& operator-=(size_t i) { m_inc -= i; return *this; }
// and loads of others
private:
size_t m_inc;
};