Prenons le cas d'une fonction basée sur un modèle avec des arguments de modèle variadiques:
template<typename Tret, typename... T> Tret func(const T&... t);
Maintenant, j'ai un tuple t
de valeurs. Comment appeler en func()
utilisant les valeurs de tuple comme arguments? J'ai lu sur l' bind()
objet fonction, avec call()
fonction, et aussi sur la apply()
fonction dans différents documents maintenant obsolètes. L'implémentation de GNU GCC 4.4 semble avoir une call()
fonction dans la bind()
classe, mais il y a très peu de documentation sur le sujet.
Certaines personnes suggèrent des hacks récursifs écrits à la main, mais la vraie valeur des arguments de modèle variadique est de pouvoir les utiliser dans des cas comme ci-dessus.
Quelqu'un a-t-il une solution ou un indice sur où en savoir plus?
integer_sequence
, voir en.cppreference.com/w/cpp/utility/integer_sequenceinteger_sequence S
, vous appelez simplement votre fonction en tant quefunc(std::get<S>(tuple)...)
et laissez le compilateur gérer le reste.Réponses:
Voici mon code si quelqu'un est intéressé
Fondamentalement, au moment de la compilation, le compilateur déroulera récursivement tous les arguments dans divers appels de fonction inclusifs <N> -> appelle <N-1> -> appelle ... -> appelle <0> qui est le dernier et le compilateur optimisera loin les différentes fonctions intermédiaires appellent à ne garder que la dernière qui est l'équivalent de func (arg1, arg2, arg3, ...)
Deux versions sont fournies, une pour une fonction appelée sur un objet et l'autre pour une fonction statique.
la source
tr1
peut être retiré maintenant avec c ++ 11En C ++ 17, vous pouvez faire ceci:
Cela fonctionne déjà dans Clang ++ 3.9, en utilisant std :: experimental :: apply.
En réponse au commentaire disant que cela ne fonctionnera pas s'il
the_function
est basé sur un modèle, voici une solution de contournement:Cette solution de contournement est une solution simplifiée au problème général du passage des ensembles de surcharge et du modèle de fonction là où une fonction serait attendue. La solution générale (celle qui prend en charge le transfert parfait, la constexpr-ness et le noexcept-ness) est présentée ici: https://blog.tartanllama.xyz/passing-overload-sets/ .
la source
the_function
est basé sur un modèle.std::apply(add_generic<float>, std::make_pair(2.0f, 3.0f));
En C ++, il existe de nombreuses façons de développer / décompresser un tuple et d'appliquer ces éléments de tuple à une fonction de modèle variadique. Voici une petite classe d'assistance qui crée un tableau d'index. Il est beaucoup utilisé dans la métaprogrammation de modèles:
Maintenant, le code qui fait le travail n'est pas si gros:
Le test est montré ci-dessous:
Je ne suis pas un grand expert dans d'autres langues, mais je suppose que si ces langues n'ont pas une telle fonctionnalité dans leur menu, il n'y a aucun moyen de le faire. Au moins avec C ++, vous pouvez, et je pense que ce n'est pas si compliqué ...
la source
template<class ... T> void three(T...) {}
et que j'essaie d'utiliser, appliquez dessus, il ne compile pas.Je trouve que c'est la solution la plus élégante (et elle est transmise de manière optimale):
Exemple d'utilisation:
Malheureusement, GCC (4.6 au moins) ne parvient pas à compiler cela avec "désolé, non implémenté: mangling overload" (ce qui signifie simplement que le compilateur n'implémente pas encore complètement la spécification C ++ 11), et comme il utilise des modèles variadiques, il ne sera pas travailler dans MSVC, donc c'est plus ou moins inutile. Cependant, une fois qu'il y aura un compilateur qui prend en charge la spécification, ce sera la meilleure approche à mon humble avis. (Remarque: ce n'est pas si difficile de modifier cela pour pouvoir contourner les lacunes de GCC, ou de l'implémenter avec Boost Preprocessor, mais cela ruine l'élégance, c'est donc la version que je publie.)GCC 4.7 prend désormais en charge ce code très bien.
Edit: Ajout de l'avant autour de l'appel de fonction réel pour prendre en charge le formulaire de référence rvalue * au cas où vous utiliseriez clang (ou si quelqu'un d'autre se contente de l'ajouter).
Edit: Ajout de l'avant manquant autour de l'objet de fonction dans le corps de la fonction d'application non membre. Merci à pheedbaq d'avoir signalé qu'il manquait.
Edit: Et voici la version C ++ 14 juste parce qu'elle est tellement plus agréable (ne compile pas encore):
Voici une version pour les fonctions membres (peu testée!):
la source
apply
, pourquoi n'estf
pas encapsulé avec unstd::forward
appel, comme c'est le cas dans le type de retour? N'est-ce pas nécessaire?foo('x', true)
compilé exactement le même code d'assemblageapply(foo, ::std::make_tuple('x', true))
qu'avec n'importe quel niveau d'optimisation en plus de -O0.integer_sequence
vous obtenez même une implémentation presque correcte deapply()
dans son exemple. voir ma réponse ci-dessous.Ceci est adapté du brouillon de C ++ 14 en utilisant index_sequence. Je pourrais proposer de l'appliquer dans une future norme (TS).
la source
Les nouvelles ne semblent pas bonnes.
Après avoir lu le projet de norme qui vient d'être publié , je ne vois pas de solution intégrée à cela, ce qui semble étrange.
Le meilleur endroit pour poser des questions sur de telles choses (si vous ne l'avez pas déjà fait) est comp.lang.c ++. Modéré, car certaines personnes participent régulièrement à la rédaction du message standard.
Si vous consultez ce fil , quelqu'un a la même question (peut-être que c'est vous, auquel cas vous allez trouver toute cette réponse un peu frustrante!), Et quelques implémentations horribles sont suggérées.
Je me suis juste demandé s'il serait plus simple de faire accepter la fonction a
tuple
, car la conversion de cette façon est plus facile. Mais cela implique que toutes les fonctions doivent accepter les tuples comme arguments, pour une flexibilité maximale, et cela démontre simplement l'étrangeté de ne pas fournir une extension intégrée du tuple en pack d'arguments de fonction.Mise à jour: le lien ci-dessus ne fonctionne pas - essayez de coller ceci:
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/750fa3815cdaac45/d8dc09e34bbb9661?lnk=gst&q=tuple+variadic#d8dc09e34bbb9661
la source
Toutes ces implémentations sont bonnes. Mais en raison de l'utilisation d'un pointeur vers une fonction membre, le compilateur ne peut souvent pas insérer l'appel de la fonction cible (au moins gcc 4.8 ne peut pas, quoi qu'il en soit Pourquoi gcc ne peut pas insérer des pointeurs de fonction qui peuvent être déterminés? )
Mais les choses changent si vous envoyez le pointeur vers la fonction membre en tant qu'arguments de modèle, pas en tant que paramètres de fonction:
Et utilisation:
Preuve d'inlinable http://goo.gl/5UqVnC
Avec de petits changements, on peut "surcharger"
apply_tuple
:De plus, c'est la seule solution qui fonctionne avec des fonctions basées sur des modèles.
la source
1) si vous avez une structure parameter_pack prête à l'emploi comme argument de fonction, vous pouvez simplement utiliser std :: tie comme ceci:
2) Si vous n'avez pas d'argument parampack prêt à l'emploi, vous devrez dérouler le tuple comme ceci
la source
Que dis-tu de ça:
Le
run_tuple
modèle de fonction prend le tuple donné et transmet ses éléments individuellement à la fonction donnée. Il effectue son travail en appelant de manière récursive ses modèles de fonctions d'assistanceexplode_tuple
. Il est important derun_tuple
transmettre la taille du tuple àexplode_tuple
; ce nombre agit comme un compteur pour le nombre d'éléments à extraire.Si le tuple est vide,
run_tuple
appelle la première version deexplode_tuple
avec la fonction distante comme seul autre argument. La fonction distante est appelée sans argument et nous avons terminé. Si le tuple n'est pas vide, un nombre plus élevé est passé à la deuxième version deexplode_tuple
, avec la fonction distante. Un appel récursif àexplode_tuple
est fait, avec les mêmes arguments, sauf que le nombre de compteur est diminué de un et (une référence à) le dernier élément de tuple est ajouté comme argument après la fonction distante. Dans un appel récursif, soit le compteur n'est pas nul, et un autre appel est effectué avec le compteur diminué à nouveau et l'élément suivant non référencé est inséré dans la liste d'arguments après la fonction distante mais avant les autres arguments insérés, soit le compteur atteint zéro et la fonction distante est appelée avec tous les arguments accumulés après elle.Je ne suis pas sûr d'avoir la syntaxe pour forcer une version particulière d'un modèle de fonction à droite. Je pense que vous pouvez utiliser un pointeur vers une fonction comme objet de fonction; le compilateur le corrigera automatiquement.
la source
J'évalue MSVS 2013RC, et il n'a pas réussi à compiler certaines des solutions précédentes proposées ici dans certains cas. Par exemple, MSVS ne parviendra pas à compiler les retours «auto» s'il y a trop de paramètres de fonction, en raison d'une limite d'imbrication d'espace de noms (j'ai envoyé cette information à Microsoft pour qu'elle soit corrigée). Dans d'autres cas, nous avons besoin d'accéder au retour de la fonction, bien que cela puisse également être fait avec un lamda: les deux exemples suivants donnent le même résultat.
Et merci encore à ceux qui ont posté des réponses ici avant moi, je ne serais pas arrivé à ça sans cela ... alors la voici:
la source
const
?En vous étendant sur la solution de @ David, vous pouvez écrire un modèle récursif qui
integer_sequence
sémantique (trop verbeuse, imo)int N
pour compter les itérations récursivesPar exemple:
Alternativement, si votre foncteur n'est pas défini au moment de la compilation (par exemple, une
constexpr
instance non fonctionnelle ou une expression lambda), vous pouvez l'utiliser comme paramètre de fonction au lieu d'un paramètre de modèle de classe, et en fait supprimer entièrement la classe contenant:Pour les callables de fonction pointeur vers membre, vous pouvez ajuster l'un des morceaux de code ci-dessus de la même manière que dans la réponse de @ David.
Explication
En référence au deuxième morceau de code, il existe deux fonctions de modèle: la première prend le foncteur
func
, le tuplet
avec les typesT...
et un packargs
de paramètres de typesArgs_tmp...
. Lorsqu'il est appelé, il ajoute de manière récursive les objets dut
pack de paramètres un à la fois, du début (0
) à la fin, et appelle à nouveau la fonction avec le nouveau pack de paramètres incrémenté.La signature de la deuxième fonction est presque identique à la première, sauf qu'elle utilise le type
T...
pour le pack de paramètresargs
. Ainsi, une fois queargs
la première fonction est complètement remplie avec les valeurs det
, son type seraT...
(dans psuedo-code,typeid(T...) == typeid(Args_tmp...)
), et donc le compilateur appellera à la place la deuxième fonction surchargée, qui à son tour appellefunc(args...)
.Le code de l'exemple de foncteur statique fonctionne de manière identique, le foncteur étant à la place utilisé comme argument de modèle de classe.
la source
Pourquoi ne pas simplement envelopper vos arguments variadiques dans une classe de tuple, puis utiliser la récursivité au moment de la compilation (voir le lien ) pour récupérer l'index qui vous intéresse. Je trouve que décompresser les modèles variadiques dans un conteneur ou une collection peut ne pas être de type sûr pour des types hétérogènes
la source
Args...
->tuple
, maistuple
->Args...
.Cette solution simple fonctionne pour moi:
la source