Итератор с алгоритмами STL и std :: execute :: par Политика выполнения - PullRequest
0 голосов
/ 05 июля 2018

Как использовать Итератор при указании политики выполнения std::execution::par для алгоритма STL, такого как 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;
}

Насколько мне известно, приведенный выше код потокобезопасен . Однако как можно достичь такого же эффекта с помощью итератора в поточно-ориентированном режиме , не генерируя сначала нужные индексы, как описано выше? Предполагается, что в контейнере, для которого выполняется итерация, не реализован итератор, или нет итератора, поточно-безопасного .

В идеале я хотел бы сделать это в общем (я знаю, что у Эйгена есть итераторы, он используется здесь только в качестве примера).

Кроме того, было бы крайне предпочтительно использовать только функции C ++ (без библиотек, но без стандарта).

1 Ответ

0 голосов
/ 05 июля 2018

Вы можете использовать что-то вроде 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; 
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...