Можно ли использовать boost :: filter_iterator для вывода? - PullRequest
7 голосов
/ 31 августа 2011

Я использую std::transform с std::back_inserter для добавления элементов к std::deque.Теперь преобразование может завершиться неудачно и в некоторых случаях вернет недопустимый объект (скажем, неинициализированный boost::optional или нулевой указатель).Я хотел бы отфильтровать недопустимые объекты от добавления.

Я думал об использовании boost::filter_iterator, но не уверен, как представить параметр end() отфильтрованного диапазона.

документация boost::filter_iterator предполагает, что возможна фильтрация выходных данных.Должен ли я просто специализировать operator == для std::back_insert_iterator, чтобы в этом случае всегда возвращать false?

В дополнение к этому, если я хочу добавить значения инициализированных boost::optional или указателей, могу ли я связать boost::filter_iteratorи boost::indirect_iterator?

Я пытаюсь избежать развертывания моей собственной функции transform_valid, которая принимает дополнительную функцию extractor.

Можно ли вообще использовать filter_iterator в качествевыходной итератор?

1 Ответ

8 голосов
/ 31 августа 2011

Я предлагаю использовать диапазон усиления (алгоритмы и адаптеры) для простоты использования, вы написали бы:

boost::copy(
    data | transformed(makeT) | filtered(validate) /* | indirected */, 
    std::back_inserter(queue));

Вот полный рабочий пример этого:

#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/optional.hpp>

#include <vector>
#include <deque>

typedef boost::optional<int> T;
typedef std::deque<T> Q;

static T makeT(int i)
{
    if (i%2) return T();
    else     return i;
}

static bool validate(const T& optional) 
{ 
    return (bool) optional; // select the optional that had a value set
}

int main()
{
    static const int data[] =  { 1,2,3,4,5,6,7,8,9 };

    Q q;

    using boost::adaptors::filtered;
    using boost::adaptors::transformed;

    // note how Boost Range elegantly supports an int[] as an input range
    boost::copy(data | transformed(makeT) | filtered(validate), std::back_inserter(q));

    // demo output: 2, 4, 6, 8 printed
    for (Q::const_iterator it=q.begin(); it!=q.end(); ++it)
    {
        std::cout << (*it? "set" : "unset") << "\t" << it->get_value_or(0) << std::endl;
    }

    return 0;
}

Обновление

С небольшой помощью из этого ответа: Используйте boost :: опционально вместе с boost :: adapters :: indirected

Теперь я включаюэлегантная демонстрация использования адаптера диапазона indirected для немедленного вывода очереди (разыменование опций):

Обратите внимание, что для (интеллектуальных) типов указателей будет очевидно, не нужно указывать специализацию pointee<>.Я считаю, что это по замыслу: optional<> is not, and does not model, a pointer

#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

#include <boost/optional.hpp>

namespace boost {
    template<typename P> struct pointee<optional<P> > {
        typedef typename optional<P>::value_type type;
    };
}

typedef boost::optional<int> T;

static T    makeT(int i)                { return i%2?  T() : i; }
static bool validate(const T& optional) { return (bool) optional; }

int main() {
    using namespace boost::adaptors;

    static int data[] =  { 1,2,3,4,5,6,7,8,9 };
    boost::copy(data | transformed(makeT) 
                     | filtered(validate) 
                     | indirected, 
                     std::ostream_iterator<int>(std::cout, ", "));
}
...