Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

[Aller plus loin] C++ - Extraire des collections de données depuis une collection initiale
Un billet blog de Bousk

Le , par Bousk

0PARTAGES

Dans le billet précédent, nous avons vu comment extraire des collections de données depuis un vector sans aucune allocation supplémentaire.
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; 
};
Et nous pouvons créer des allias pour continuer à utiliser VectorView aisément:
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)...); 
}
Enfin, petite mise à jour similaire pour notre petite fonction d'affichage de collection:
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; 
}

Une erreur dans cette actualité ? Signalez-le nous !