2010-05-09 25 views
3

Je voulais écrire une fonction d'ordre supérieur filter avec C++. Le code que je suis venu avec est à ce jour comme suit:Fonction «ordre» d'ordre supérieur en C++

#include <iostream> 
#include <string> 
#include <functional> 
#include <algorithm> 
#include <vector> 
#include <list> 
#include <iterator> 

using namespace std; 

bool isOdd(int const i) { 
    return i % 2 != 0; 
} 

template < 
    template <class, class> class Container, 
    class Predicate, 
    class Allocator, 
    class A 
> 
Container<A, Allocator> filter(Container<A, Allocator> const & container, Predicate const & pred) { 
    Container<A, Allocator> filtered(container); 
    container.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end()); 
    return filtered; 
} 

int main() { 
    int const a[] = {23, 12, 78, 21, 97, 64}; 
    vector<int const> const v(a, a + 6); 
    vector<int const> const filtered = filter(v, isOdd); 
    copy(filtered.begin(), filtered.end(), ostream_iterator<int const>(cout, " ")); 
} 

Cependant sur la compilation de ce code, je reçois les messages d'erreur suivants que je suis incapable de comprendre et donc se débarrasser de:

/usr/include/c++/4.3/ext/new_allocator.h: In instantiation of ‘__gnu_cxx::new_allocator<const int>’: 
/usr/include/c++/4.3/bits/allocator.h:84: instantiated from ‘std::allocator<const int>’ 
/usr/include/c++/4.3/bits/stl_vector.h:75: instantiated from ‘std::_Vector_base<const int, std::allocator<const int> >’ 
/usr/include/c++/4.3/bits/stl_vector.h:176: instantiated from ‘std::vector<const int, std::allocator<const int> >’ 
Filter.cpp:29: instantiated from here 
/usr/include/c++/4.3/ext/new_allocator.h:82: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const [with _Tp = const int]’ cannot be overloaded 
/usr/include/c++/4.3/ext/new_allocator.h:79: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const int]’ 
Filter.cpp: In function ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool()(int), Allocator = std::allocator<const int>, A = const int]’: 
Filter.cpp:30: instantiated from here 
Filter.cpp:23: error: passing ‘const std::vector<const int, std::allocator<const int> >’ as ‘this’ argument of ‘__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::erase(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >) [with _Tp = const int, _Alloc = std::allocator<const int>]’ discards qualifiers 
/usr/include/c++/4.3/bits/stl_algo.h: In function ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _Predicate = bool (*)(int)]’: 
Filter.cpp:23: instantiated from ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool()(int), Allocator = std::allocator<const int>, A = const int]’ 
Filter.cpp:30: instantiated from here 
/usr/include/c++/4.3/bits/stl_algo.h:821: error: assignment of read-only location ‘__result.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = const int*, _Container = std::vector<const int, std::allocator<const int> >]()’ 
/usr/include/c++/4.3/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::deallocate(_Tp*, size_t) [with _Tp = const int]’: 
/usr/include/c++/4.3/bits/stl_vector.h:150: instantiated from ‘void std::_Vector_base<_Tp, _Alloc>::_M_deallocate(_Tp*, size_t) [with _Tp = const int, _Alloc = std::allocator<const int>]’ 
/usr/include/c++/4.3/bits/stl_vector.h:136: instantiated from ‘std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = const int, _Alloc = std::allocator<const int>]’ 
/usr/include/c++/4.3/bits/stl_vector.h:286: instantiated from ‘std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const _Alloc&) [with _InputIterator = const int*, _Tp = const int, _Alloc = std::allocator<const int>]’ 
Filter.cpp:29: instantiated from here 
/usr/include/c++/4.3/ext/new_allocator.h:98: error: invalid conversion from ‘const void*’ to ‘void*’ 
/usr/include/c++/4.3/ext/new_allocator.h:98: error: initializing argument 1 of ‘void operator delete(void*)’ 
/usr/include/c++/4.3/bits/stl_algobase.h: In function ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false, _II = const int*, _OI = const int*]’: 
/usr/include/c++/4.3/bits/stl_algobase.h:435: instantiated from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false, _II = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _OI = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >]’ 
/usr/include/c++/4.3/bits/stl_algobase.h:466: instantiated from ‘_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _OI = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >]’ 
/usr/include/c++/4.3/bits/vector.tcc:136: instantiated from ‘__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::erase(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >) [with _Tp = const int, _Alloc = std::allocator<const int>]’ 
Filter.cpp:23: instantiated from ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool()(int), Allocator = std::allocator<const int>, A = const int]’ 
Filter.cpp:30: instantiated from here 
/usr/include/c++/4.3/bits/stl_algobase.h:396: error: no matching function for call to ‘std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m(const int*&, const int*&, const int*&)’ 

S'il vous plaît dites-moi ce que je fais mal ici et quelle est la bonne façon d'obtenir le type de polymorphisme d'ordre supérieur que je veux.

Merci.

EDIT:

Merci, tout le monde. Voici le nouveau code je suis arrivé après avoir appliqué vos suggestions (et il fonctionne maintenant, youpi!)

#include <iostream> 
#include <string> 
#include <functional> 
#include <algorithm> 
#include <vector> 
#include <list> 
#include <iterator> 

using namespace std; 

bool isOdd(int const i) { 
    return i % 2 != 0; 
} 

template < 
    template <typename, typename> class Container, 
    typename Predicate, 
    typename Allocator, 
    typename A 
> 
Container<A, Allocator> filter(Container<A, Allocator> const & container, Predicate const & pred) { 
    Container<A, Allocator> filtered(container); 
    filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end()); 
    return filtered; 
} 

int main() { 
    int a[] = {23, 12, 78, 21, 97, 64}; 
    vector<int> v(a, a + 6); 
    vector<int> filtered = filter(v, isOdd); 
    copy(filtered.begin(), filtered.end(), ostream_iterator<int>(cout, " ")); 
} 
+0

Cette fonction ne serait-elle pas chère? Vous copiez un conteneur, filtrez la copie, puis renvoyez la copie filtrée par valeur. Pourquoi ne pas simplement utiliser 'remove_if()' directement sur le conteneur d'origine? Ou, créez une fonction d'alias 'filter()' qui prend les itérateurs, puis appelle 'remove_if()'? – wilhelmtell

Répondre

5

Pourquoi votre Container paramétrés du tout?

template <typename C, typename P> 
C filter(C const & container, P pred) { 
    C filtered(container); 
    filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end()); 
    return filtered; 
} 

Fonctionne tout aussi bien. Notez que j'ai passé P par valeur plutôt que par référence const, comme conseillé par Meyers dans Effective C++ (les itérateurs et les foncteurs doivent être passés par valeur).

+0

Que faire si je veux accéder au paramètre de type du conteneur? –

+3

@Red Hyena: Alors vous faites 'typename C :: value_type' – UncleBens

+0

Encore une question ... Pourquoi ne pas passer les itérateurs et les foncteurs par référence? –

3

L'erreur est pas filter, mais:

int main() { 
    int const a[] = {23, 12, 78, 21, 97, 64}; 
    vector<int const> const v(a, a + 6); 
} 

You can't have a vector of const stuff. Retirez la const intérieure: (. Et bien sûr, filtered.erase, non container.erase)

int main() { 
    int const a[] = {23, 12, 78, 21, 97, 64}; 
    vector<int> const v(a, a + 6); 
} 

4

Qu'en est-remove_copy_if à la place? (avec isEven()). C'est déjà construit pour toi.

+0

Ou alors, implémentez 'copy_if'. En C++, il est plus idiomatique de travailler avec les itérateurs qu'avec les conteneurs. –

0

container est une référence constante. Vous ne pouvez pas appeler erase() dessus. Vous voulez probablement appeler

filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end());