2016-08-02 5 views
5

Существуют различные алгоритмы STL, которые полагаются на выходной итератор для хранения результата алгоритма.Адаптер выходного итератора для подсчета, но не для копирования

Например, std::set_intersection сохранит все общие элементы между двумя отсортированными диапазонами в выходном итераторе, который затем будет увеличиваться после каждого выводимого элемента.

Иногда меня не интересуют фактические элементы, а только количество выходных элементов. В таких случаях копия элементов является пустой тратой памяти и производительности. Есть ли адаптер итератора, который я могу использовать для подсчета и избежания копирования элементов? Если вы не можете предложить общую реализацию такого адаптера?

+0

Голосование, чтобы закрыть как запрос ресурсов, но вы можете [ 'повышение :: counting_iterator'] (http://www.boost.org/doc/libs/1_50_0/libs/iterator/doc/counting_iterator. html) – NathanOliver

+0

Ваш вопрос немного неясен: вы хотите знать, сколько элементов будет содержать пересечение двух множеств без вычисления пересечения? – wasthishelpful

+0

@wasthishelpful Да, в моем примере set_difference, но я ищу универсальное решение итератора Ouput для любого такого алгоритма. – T33C

ответ

0

Благодаря большой помощи от @ecatmur ответа и комментариев, у меня есть следующее решение, которое я приглашаю комментарии. Я надеялся, что работаю boost::make_function_output_iterator, но кажется, что в библиотеке есть ошибка, которая не может определить оператор присваивания.

#include <algorithm> 
#include <vector> 
#include <iostream> 
#include <string> 
#include <cassert> 

class counting_output_iterator 
{ 
public: 
    counting_output_iterator& operator=(const counting_output_iterator&) { return *this; }; 
    explicit counting_output_iterator(std::size_t& count) : m_count(count) {} 
    template<typename T> void operator=(const T&) {}; //NULL op 
    using iterator_category = std::output_iterator_tag; 
    using value_type = void; 
    using difference_type = void; 
    using pointer = void; 
    using reference = void;  
    counting_output_iterator& operator*() { return *this; } 
    counting_output_iterator& operator++() { ++m_count; return *this; } 
    std::size_t& m_count; 
}; 

int main(int, char*[]) 
{ 
    std::vector<int> arr{ 1,2,3,4 }; 
    std::size_t count = 0; 
    std::copy(std::begin(arr), std::end(arr), counting_output_iterator{ count }); 
    assert(count == 4u); 
    return 0; 
} 
4

подталкивания-х Function Output Iterator может делать то, что вы хотите:

std::size_t count = 0u; 
int arr[]{0, 1, 2, 3}; 
std::copy(std::begin(arr), std::end(arr), 
    boost::make_function_output_iterator([&](auto const&) { ++count; })); 
assert(count == 4u); 

Единственная проблема в том, что вы должны объявить переменную счетчика вне итератора, потому что нет никакого способа, чтобы извлечь хранимую функцию объекта из boost::function_output_iterator (и также невозможно извлечь значения закрытия из лямбда, даже если вы преодолели это препятствие). Если вы хотите писать однострочные шрифты, вам нужно будет написать класс итератора самостоятельно, но это не очень большой код; например:

class counting_output_iterator { 
public: 
    using iterator_category = std::output_iterator_tag; 
    using value_type = void; 
    using difference_type = void; 
    using pointer = void; 
    using reference = void; 

    std::size_t value = 0u; 

    struct output_proxy { 
    output_proxy(std::size_t& value) : m_value(value) { } 
    template<class T> output_proxy& operator=(T const&) { 
     ++m_value; 
     return *this; 
    } 
    std::size_t& m_value; 
    }; 
    output_proxy operator*() { return output_proxy(value); } 
    counting_output_iterator& operator++() { return *this; } 
    counting_output_iterator& operator++(int) { return *this; } 
}; 

Использование:

int arr[]{0, 1, 2, 3}; 
auto const count = std::copy(std::begin(arr), std::end(arr), 
    counting_output_iterator{}).value; 
assert(count == 4u); 
+0

Выглядит многообещающе, но код не компилируется в VS2015U2 с Boost 1.59. Попытка ссылки на удаляемую функцию. Я заменил функтор, который компилируется, но считается 6 вместо 3. Странно! Я все еще расследую. Спасибо за ваше предложение. – T33C

+0

Вы внесли существенные изменения, так как я прокомментировал это, пытаясь первыми, что может привести к аннулированию моего комментария выше. Спасибо за вашу помощь. – T33C

+0

Лямбда-решение все еще не работает. Counting_output_operator работает, но зависит от алгоритма, возвращающего выходной итератор, иначе значение не доступно. Вы поставили меня на правильный путь, и я буду экспериментировать больше. – T33C