1
votes

Développer std :: vector dans le pack de paramètres

J'ai des méthodes avec la signature suivante:

void CallDoStuff(const std::vector<int>& vElements) {
  // What magic is supposed to happen here to make vElements an expandable pack?
  DoStuff(vElemets...);
}

J'ai une méthode à partir de laquelle je voudrais appeler les méthodes DoStuff comme suit:

void DoStuff(int i);
void DoStuff(int i, k);
void DoStuff(int i, int k, int l);


0 commentaires

3 Réponses :


0
votes

Cela ne peut pas être fait, un appel de méthode de modèle est lié au moment de la compilation mais un std :: vector ne sait pas combien d'éléments il contient avant l'exécution, il n'y a donc aucun moyen de mélanger le deux concepts.

DoStuff(vElemets...);

Ici, le compilateur doit choisir l'implémentation correcte en fonction du nombre d'éléments de vElements . Vous voyez la faille dans ce genre de pensée puisque std :: vector est juste un objet qui pourrait contenir n'importe quelle quantité d'éléments au point d'invocation.


1 commentaires

Comme déjà répondu à max66, je suis tout à fait d'accord avec vous Jack, les modèles doivent connaître la taille au compilation et la taille du vecteur n'est connue qu'au exécution .



0
votes

Le problème est qu'à partir d'un std :: vector , vous ne pouvez pas - compiler temps - extraire le size () value.

Ainsi, vous ne pouvez obtenir ce que vous voulez que si vous passez, comme valeur connue à la compilation, à CallDoStuff () le nombre d'éléments que vous que vous souhaitez utiliser à partir du vecteur.

Vous pouvez le transmettre comme valeur de modèle, par exemple.

En utilisant une fonction d'assistance, vous pouvez écrire quelque chose comme suit

XXX

L'appel pourrait être quelque chose comme

std::array<int, 5u>  arr { 2, 3, 5, 7, 11 };

CallDoStuff(arr); // no more <5u>

Si vous pouvez utiliser un std :: array , au lieu de std :: vector , la réponse est différente: vous pouvez extraire le size () du type lui-même, donc

template <std::size_t N, std::size_t ... Is>
void CallDoStuff (std::array<int, N> const & vElements,
                  std::index_sequence<Is...> const &)
 { DoStuff(vElements[Is]...); }

template <std::size_t N>
void CallDoStuff (std::array<int, N> const & vElements)
 { CallDoStuff(vElements, std::make_index_sequence<N>{}); }

qui est appelable sans expliquer N comme suit

CallDoStuff<5u>(v);

Note de fin: observez que std :: make_index_sequence et std :: index_sequence ne sont disponibles qu'à partir de C ++ 14. En C ++ 11, vous devez les remplacer d'une manière ou d'une autre.


3 commentaires

Je suis totalement d'accord avec vous, les modèles doivent connaître la taille au moment de la compilation et la taille du vecteur n'est connue qu'au moment de l'exécution.


Si vous utilisez std :: array, std :: apply est une solution simple.


@ JakeDenham-Dyson - Voulez-vous dire std :: apply (DoStuff, arr); ? Malheureusement, dans ce cas, cela ne fonctionne pas de manière aussi simple: DoStuff () est une fonction surchargée donc le compilateur ne peut pas sélectionner la bonne version. De plus, std :: apply () est introduit dans C ++ 17 et la question est étiquetée C ++ 11 (mais c'est aussi un problème de ma réponse qui est C ++ 14).



0
votes

C'est possible, à condition de fournir une limite supérieure au nombre d'arguments.

Utilisation de l'implémentation de Xeo de std :: index_sequence pour C ++ 11:

template <unsigned... Idx>
void trampoline(const std::vector<int>& vElements, seq<Idx...>) {
    return DoStuff(vElements[Idx]...);
}

template <std::size_t Arity>
void trampoline(const std::vector<int>& vElements) {
    return trampoline(vElements, typename gen_seq<Arity>::seq{});
}

template <unsigned... Idx>
void CallDoStuff(const std::vector<int>& vElements, seq<Idx...>) {
    using trampoline_t = void (*)(const std::vector<int>&);
    constexpr trampoline_t trampolines[]{
        trampoline<Idx>...
    };
    trampolines[vElements.size()](vElements);
}

template <std::size_t Max>
void CallDoStuff(const std::vector<int>& vElements) {
    assert(vElements.size() <= Max);
    return CallDoStuff(vElements, typename gen_seq<Max + 1>::seq{});
}

Regardez-le en direct sur Wandbox


1 commentaires

Cette réponse résout le mieux mon problème, car je peux encapsuler l'appel de fonction CallDoStuff <3u> (vElements). Mais toutes les autres réponses sont également correctes.