1. #1
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 301
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 301
    Points : 3 784
    Points
    3 784

    Par défaut Expansion de parameter pack appliquée aux integer_sequence

    En cherchant comment générer une séquence de nombres entiers à partir de paramètres template selon des règles définies par moi-même, je suis tombé sur cette réponse de Jarod42 sur SO qui me dépasse un peu.

    Je me suis permis de reproduire son exemple ci-dessous, traduit en C++17 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <type_traits>
    #include <utility>
     
    namespace detail
    {
        template <typename Seq1, std::size_t Offset, typename Seq2> struct concat_seq;
     
        template         <std::size_t            ...Is1, std::size_t Offset, std::size_t            ...Is2>
        struct concat_seq<std::index_sequence<Is1...>  ,             Offset, std::index_sequence<Is2...>  >
        {
            using type = std::index_sequence<Is1..., (Offset + Is2)...>;
        };
    }
     
    template <std::size_t N, std::size_t E>
    using gen_seq = typename detail::concat_seq<typename std::make_index_sequence<E>, E + 1, typename std::make_index_sequence<(N > E) ? (N - E - 1) : 0>>::type;
     
    static_assert(std::is_same_v<std::index_sequence<0, 1,    3, 4>, gen_seq<5, 2>>);
    static_assert(std::is_same_v<std::index_sequence<   1, 2      >, gen_seq<3, 0>>);
    static_assert(std::is_same_v<std::index_sequence<0, 1, 2, 3   >, gen_seq<4, 4>>);
    J'ai une question simple bien qu'un peu générale, certes : comment ça marche ? J'ai bien une vague idée de ce qu'il se passe mais j'aimerais saisir les détails. En particulier : que fait (Offset + Is2)... ?

  2. #2
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    5 263
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 5 263
    Points : 22 360
    Points
    22 360

    Par défaut

    Salut,

    c'est du template bien velu pour générer des listes d'entiers à la compilation.
    index_sequence<0,1,2,3> crée une structure avec paramètres template de type size_t valant 0, 1, 2 et 3. Et tu as des helpers comme make_index_sequence<A> pour générer <0, ..., A-1>
    Sur SO tu peux lire que le but de gen_seq<A, B> est de générer une telle liste de 0 à A exclus en skippant B.

    Tu peux voir que concat_seq fait juste une concaténation de 2 séquences. Les séquences sont séparées par cet offset dans les paramètres qui est appliqué à chaque élément de la 2° séquence.

    Avec gen_seq<N, E> tu as
    - La première séquence est typename std::make_index_sequence<E> qui génère <0, ..., E-1>
    - E + 1 sert d'offset
    - La deuxième séquence est typename std::make_index_sequence<(N > E) ? (N - E - 1) : 0 qui génère <0, ..., N-E-2> si N > E, un ensemble vide <> sinon

    gen_seq<5, 2>
    - séquence 1 : <0, 1>
    - offset : 2+1=3
    - séquence 2 : 5-2-1=2 : <0, 1>
    en concaténant le tout on retrouve <0, 1, 0+3, 1+3> = <0, 1, 3, 4>
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 301
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 301
    Points : 3 784
    Points
    3 784

    Par défaut

    Oui d'accord, je vois à peu près. Ma confusion vient du fait qu'instinctivement j'aurais cherché à implémenter la solution différemment, sans doute à base de tag dispatch ou d'enable_if.. J'ai probablement une vision un peu trop « impérative » de la chose.

    Donc (Offset + Is2)... applique Offset + à tous les éléments de la séquence Is2, ok.

    Il y a encore un point qui m'échappe, les lignes 8 et 9 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        template         <std::size_t            ...Is1, std::size_t Offset, std::size_t            ...Is2>
        struct concat_seq<std::index_sequence<Is1...>  ,             Offset, std::index_sequence<Is2...>  >
    S'agit-il d'une spécialisation ? Pourquoi les paramètres templates sont-ils ainsi « répétés » et comment sont-ils sélectionnés/appliqués lors de la déclaration de gen_seq ?

  4. #4
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    5 263
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 5 263
    Points : 22 360
    Points
    22 360

    Par défaut

    Tu ne peux normalement pas avoir 2 variadic template dans un template. Logiquement, puisque ... englobe déjà tous les paramètres.
    Pour contourner cette limite, on ne passe pas directement les paramètres template mais la struct index_sequence (qui prend des variadic template et doivent donc être déclarés).
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 301
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 301
    Points : 3 784
    Points
    3 784

    Par défaut

    Je n'ai pas encore vraiment eu le temps de me remettre au travail sur la branche en question mais je pense avoir mieux saisi la syntaxe utilisée, merci.

    J'ai implémenté une petite variation qui me permet de générer une répétition d'un même entier encadrée par deux autres entiers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <climits>
    #include <type_traits>
    #include <utility>
     
     
    namespace detail {
        template <typename T, std::enable_if_t<std::is_integral_v<T>, T> Filler, T Prefix, std::size_t N, T ...Elements>
        struct repeat_seq {
            using type = typename repeat_seq<T, Filler, Prefix, N - 1, Filler, Elements...>::type;
        };
     
        template <typename T, std::enable_if_t<std::is_integral_v<T>, T> Filler, T Prefix, T ...Elements>
        struct repeat_seq<T, Filler, Prefix, std::size_t(0u), Elements...> {
            using type = std::integer_sequence<T, Prefix, Elements...>;
        };
    }
     
    template <int Prefix, int Filler, std::size_t N, int Suffix>
    using gen_seq = typename detail::repeat_seq<int, Filler, Prefix, N, Suffix>::type;
     
     
    static_assert(std::is_same_v<std::integer_sequence<int, INT_MIN, 42, 42, 42, 42, 42, INT_MAX>, gen_seq<INT_MIN, 42, 5, INT_MAX>>);
    Ce que je veux est au final un poil plus complexe mais cela fera l'affaire pour l'instant ; j'y viendrais peut-être dans un futur post.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 15
    Dernier message: 15/12/2006, 18h18
  2. Css : Fond transparent d'un tableau s'applique aux images
    Par Orionmel dans le forum Mise en page CSS
    Réponses: 15
    Dernier message: 07/07/2006, 09h02
  3. appliquation aux maths..
    Par yakamone3 dans le forum Mathématiques
    Réponses: 8
    Dernier message: 07/06/2006, 20h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo