2013-11-21 12 views
6

Chciałem zastąpić pętli z algorytmu w poniższym kodzieNajlepszy sposób na emulowanie czegoś takiego jak warunkowe_powrót_insetu?

int numbers[] = { ... }; 
vector<int> output; 

for(int* it = numbers+from; it != numbers+to ; ++it) 
{ 
    int square = func(*it); 
    if(predicate(square)) 
    { 
     output.push_back(square); 
    } 
} 

Program ten służy do przekształcania wartości i skopiować je do miejsca przeznaczenia, jeżeli zachodzi warunek.

  • Nie mogłem użyć std::copy_if, ponieważ nie zastosowałoby to transformacji.
  • nie mogłem użyć std::transform dlatego, że brakuje orzecznik
  • To nawet nie jest dobry pomysł, aby napisać transform_copy_if(), ponieważ pośredniego kopii zmiennej przekształconej.

Wygląda na to, że moją jedyną nadzieją jest utworzenie conditional_back_insert_iterator. Wtedy mogę mieć całkiem przyzwoity połączenia jak:

int numbers[] = { ... }; 
vector<int> output; 

std::transform(numbers+from, numbers+to, 
       conditional_back_inserter(predicate, output), 
       func); 

Czy rozwiązanie to najlepszy sposób, aby traktować takie przypadki? Nie mogłem nawet używać google do wstawiania warunkowego, więc obawiam się, że jestem na niewłaściwej ścieżce.

mogłem również wyobrazić, że mogłaby wdrożyć rozwiązanie alternatywne, takie jak

std::copy_if(transform_iterator<func>(numbers+from), 
       transform_iterator<func>(numbers+to), 
       back_inserter(output)); 

(który przypomina mi przykład * filter_iterators * w Boost) ale nie oferuje czytelność.

+0

Jest zbyt wiele (użytecznych) rzeczy, które nie istnieją w Bibliotece standardowej. – Nawaz

+1

BTW, mam [bibliotekę nazywaną potokiem] (http://snawaz.github.io/foam/pipeline.html), za pomocą której możesz napisać: 'auto results = numbers | transform (func) | filter (pred); ' – Nawaz

+1

Użyłbym' copy_if' i napisałoby transformujący iterator. Boost ['function_output_iterator'] (http://www.boost.org/doc/libs/1_55_0/libs/iterator/doc/function_output_iterator.html) może być odpowiedni. – BoBTFish

Odpowiedz

3

myślę, tworząc swój własny iterator jest do zrobienia:

#include <iostream> 
#include <vector> 
#include <iterator> 
#include <functional> 

template<class T> 
class conditional_back_insert_iterator 
    : public std::back_insert_iterator<std::vector<T>> 
{ 
private: 
    using Base  = std::back_insert_iterator<std::vector<T>>; 
    using Container = std::vector<T>; 
    using value_type = typename Container::value_type; 
public: 
    template<class F> 
    conditional_back_insert_iterator(Container& other, F&& pred) 
     : Base(other), c(other), predicate(std::forward<F>(pred)) 
    { } 

    conditional_back_insert_iterator<T>& operator*() 
    { return *this; } 

    conditional_back_insert_iterator<T>& 
     operator=(const value_type& val) const 
    { 
     if (predicate(val)) 
      c.push_back(val); 
     return *this; 
    } 

    conditional_back_insert_iterator<T>& 
     operator=(value_type&& val) const 
    { 
     if (predicate(val)) 
      c.push_back(std::move(val)); 
     return *this; 
    } 
private: 
    Container& c; 
    std::function<bool (const value_type&)> predicate; 
}; 

template< 
    class Container, 
    class F, 
    class value_type = typename Container::value_type 
> 
conditional_back_insert_iterator<value_type> 
    conditional_back_inserter(Container& c, F&& predicate) 
{ 
    return conditional_back_insert_iterator<value_type>(c, std::forward<F>(predicate)); 
} 

int main() 
{ 
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    std::vector<int> to; 

    auto is_even = [] (int x) { return (x % 2) == 0; }; 

    std::copy(v.begin(), v.end(), conditional_back_inserter(to, is_even)); 
} 
0

Oto moja próba.

#include <algorithm> 
#include <iostream> 
#include <iterator> 
#include <vector> 

template <class Container, class Pred> 
class conditional_insert_iterator 
    : public std::iterator< std::output_iterator_tag, void, void, void, void > 
{ 
public: 
    explicit conditional_insert_iterator(Container& c, Pred p) : container(&c), pred(p) {} 
    conditional_insert_iterator& operator=(typename Container::const_reference value) { 
    if (pred(value)) 
     container->push_back(value); 
    return *this; 
} 

    conditional_insert_iterator& operator*() {return *this;} 
    conditional_insert_iterator& operator++() {return *this;} 
    conditional_insert_iterator& operator++(int) {return *this;} 
private: 
    Container* container; 
    Pred pred; 
}; 

template< class Container, class Pred> 
conditional_insert_iterator<Container, Pred> conditional_inserter(Container& c, Pred pred) 
{ 
    return conditional_insert_iterator<Container, Pred>(c, pred); 
} 

using namespace std; 

int main() 
{ 
    vector<int> in = { 1, 2, 3, 4, 5, 6 }; 
    vector<int> out; 
    transform(in.begin(), in.end(), 
       conditional_inserter(out, [](int i) { return i%2 == 0;}), 
       [](int i) { return i + 2;}); 
    for (auto i : out) 
     cout << i << "\n"; 

    return 0; 
} 
Powiązane problemy