La conclusion laissait entendre que ce système est applicable à d'autres collections que std::vector.
Ça l'est, et relativement simplement.
Pour y parvenir, il suffit d'ajouter un niveau de template, en modifiant le template pour pas être le type de l'élément mais de la collection.
Ainsi, VectorView devient donc ContainerView:
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | template <class Container> class ContainerView { public: using Type = Container; using Element = typename Type::value_type; using Iterator = typename Type::iterator; using ConstIterator = typename Type::const_iterator; public: ContainerView() { // Default values to prevent iterating over random memory m_begin = m_end; } ContainerView(typename ConstIterator first, typename ConstIterator end) : m_begin(first) , m_end(end) {} ConstIterator begin() const { return m_begin; } ConstIterator end() const { return m_end; } private: typename ConstIterator m_begin, m_end; }; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 | template<class T> using VectorView = ContainerView<std::vector<T>>; template<class T> using ListView = ContainerView<std::list<T>>; |
Il faut propager le changement aux fonctions.
Les plus attentifs auront remarqué que des allias sur le container interne, ses itérateurs et le type interne ont été ajouté à ContainerView. La syntaxe correspond aux types de std, mais peut être adaptée à vos propres collections.
Ceci permet de simplifier son utilisation, en passant un unique paramètre template qui sera la vue:
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template<class View> typename View::Iterator CreateLists(typename View::Iterator first, typename View::Iterator end, View& list) { list = View(first, end); return end; } template<class View> typename View::Iterator CreateLists(typename View::Iterator first, typename View::Iterator end, View& list, const std::function<bool(typename View::Element)>& extracter) { auto firstNonExtracted = std::stable_partition(first, end, extracter); list = View(first, firstNonExtracted); return firstNonExtracted; } template<class View, class... Args> void CreateLists(typename View::Iterator first, typename View::Iterator end, View& list, const std::function<bool(typename View::Element)>& extracter, Args&&... args) { auto newFirst = CreateLists<View>(first, end, list, extracter); CreateLists<View>(newFirst, end, std::forward<Args>(args)...); } |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | template<class View> void PrintValues(const char* name, View values) { std::cout << name << " : "; for (auto&& value : values) std::cout << value << ", "; std::cout << std::endl; } |
L'utilisation est identique, voire simplifiée : le paramètre template à l'appel de CreateLists, que VS2019 ne semblait pas pouvoir déduire et était obligatoire dans le premier billet, ne l'est plus !
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | int main() { { std::vector<int> values; for (int i = 0; i < 100; ++i) values.push_back(i); VectorView<int> pairs; VectorView<int> mul3; VectorView<int> mul5; VectorView<int> mul7; VectorView<int> others; CreateLists(values.begin(), values.end() , pairs, [](int v) { return v % 2 == 0; } , mul3, [](int v) { return v % 3 == 0; } , mul5, [](int v) { return v % 5 == 0; } , mul7, [](int v) { return v % 7 == 0; } , others ); PRINT_VALUES_WITH_NAME(pairs); PRINT_VALUES_WITH_NAME(mul3); PRINT_VALUES_WITH_NAME(mul5); PRINT_VALUES_WITH_NAME(mul7); PRINT_VALUES_WITH_NAME(others); } { std::list<int> values; for (int i = 0; i < 100; ++i) values.push_back(i); ListView<int> pairs; ListView<int> mul3; ListView<int> mul5; ListView<int> mul7; ListView<int> others; CreateLists(values.begin(), values.end() , pairs, [](int v) { return v % 2 == 0; } , mul3, [](int v) { return v % 3 == 0; } , mul5, [](int v) { return v % 5 == 0; } , mul7, [](int v) { return v % 7 == 0; } , others ); PRINT_VALUES_WITH_NAME(pairs); PRINT_VALUES_WITH_NAME(mul3); PRINT_VALUES_WITH_NAME(mul5); PRINT_VALUES_WITH_NAME(mul7); PRINT_VALUES_WITH_NAME(others); } return 0; } |