“déballage” un tuple pour appeler un correspondant pointeur de fonction
Je suis en train de les stocker dans un std::tuple
un nombre variable de valeurs, qui seront ensuite utilisées comme arguments pour un appel vers un pointeur de fonction qui correspond à la stockées types.
J'ai créé un exemple simplifié montrant le problème j'ai du mal à résoudre:
#include <iostream>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
void delayed_dispatch() {
//How can I "unpack" params to call func?
func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
//But I *really* don't want to write 20 versions of dispatch so I'd rather
//write something like:
func(params...); //Not legal
}
};
int main() {
int a=666;
double b = -1.234;
void *c = NULL;
save_it_for_later<int,double,void*> saved = {
std::tuple<int,double,void*>(a,b,c), f};
saved.delayed_dispatch();
}
Normalement pour les problèmes impliquant std::tuple
ou variadic templates j'écrirais un autre modèle comme template <typename Head, typename ...Tail>
à évaluer de manière récursive tous les types, un par un, mais je ne peux pas voir un moyen de le faire que pour l'envoi d'un appel de fonction.
La motivation réelle pour cela est un peu plus complexe et c'est surtout un exercice d'apprentissage de toute façon. Vous pouvez supposer que je suis a remis le tuple par contrat d'une autre interface, ne peut donc pas être changé, mais que le désir de le décompresser dans un appel de fonction est la mienne. Cette aide std::bind
comme un moyen bon marché de contourner le problème sous-jacent.
Ce qui est un moyen propre d'envoi de l'appel à l'aide de la std::tuple
, ou une alternative meilleure façon d'atteindre le même résultat net de stockage/transfert de certaines valeurs et un pointeur de fonction jusqu'à ce que l'arbitraire d'un moment de l'avenir?
auto saved = std::bind(f, a, b, c);
... puis plus tard, juste à appeler saved()
?Pas toujours mon interface de contrôle. - Je recevoir un n-uplet par contrat de quelqu'un d'autre et veulent faire des choses avec elle par la suite.
OriginalL'auteur Flexo | 2011-10-22
Vous devez vous connecter pour publier un commentaire.
Vous avez besoin pour construire un paramètre pack de chiffres et de les sortir de leur emballage
+1 en supposant que ça marche... (oups, j'ai déballé les "travaux")
Johannes, je me rends compte sa fait+ de 2 ans depuis que vous avez posté, mais la seule chose que je suis aux prises avec la
struct gens
définition générique (celui qui hérite d'un étendu dérivation de ladite même). Je le vois finalement frappe la spécialisation avec 0. Si l'ambiance vous convient et que vous avez les cycles de rechange, si vous pouvez vous étendre sur ce point, et comment il est utilisé pour cela, je vous serais éternellement reconnaissant. Et je souhaite que je pourrais haut de vote, c'est une centaine de fois. J'ai eu plus de plaisir à jouer avec les tangentes à partir de ce code. Merci.Ce qu'il fait est de générer un type
seq<0, 1, .., N-1>
. Comment cela fonctionne:gens<5>: gens<4, 4>: gens<3, 3, 4>: gens<2, 2, 3, 4> : gens<1, 1, 2, 3, 4> : gens<0, 0, 1, 2, 3, 4>
. Le dernier type est spécialisée, la création deseq<0, 1, 2, 3, 4>
. Jolie astuce.Il vaut la peine de l'écho de Walter réponse et les commentaires y afférents: folk n'avez pas besoin d'inventer leurs propres roues plus. La génération d'une séquence a été si commun qu'il a été standardisé en C++14
std::integer_sequence<T, N>
et la spécialisation de celui-ci pourstd::size_t
,std::index_sequence<N>
- en plus de leurs associés des fonctions d'assistancestd::make_in(teger|dex)_sequence<>()
etstd::index_sequence_for<Ts...>()
. Et en C++17 il y a un tas d'autres bonnes choses intégré dans la bibliothèque - notammentstd::apply
etstd::make_from_tuple
, qui permettrait de gérer le déballage et l'appel de bitsOriginalL'auteur Johannes Schaub - litb
C'est un compilable version de Johanne de la solution à awoodland est question, dans l'espoir qu'il peut être utile à quelqu'un. Cela a été testé avec un instantané de g++ 4.7 sur Debian squeeze.
On peut utiliser les éléments suivants fichier SConstruct
Sur ma machine, ce qui donne
Je suppose qu'ils ne sont pas nécessaires. J'oublie pourquoi j'ai ajouté celles-ci; elle a été près de trois ans. Mais je suppose que, pour montrer que l'instanciation des œuvres.
OriginalL'auteur Faheem Mitha
Ici est un C++14 solution.
Cela reste une fonction d'assistance (
call_func
). Puisque c'est un idiome commun, peut-être la norme doit être pris en charge directement commestd::call
avec possibilité de mise en œuvreAlors notre retard d'expédition devient
std::call
. C++14 chaotiques de zoo deinteger_sequence
etindex_sequence
helper types est expliqué ici: en.cppreference.com/w/cpp/utility/integer_sequence Avis de l'évidence de l'absence destd::make_index_sequence(Args...)
, c'est pourquoi Walter a été contraint à la clunkier syntaxestd::index_sequence_for<Args...>{}
.Et apparemment voté en C++17 depuis 3/2016 comme std::appliquer(func, tup): en.cppreference.com/w/cpp/utility/apply
OriginalL'auteur Walter
Le C++17 solution est tout simplement d'utiliser
std::apply
:Juste senti qu'il convient de rappeler une fois dans leur réponse dans ce thread (après il est déjà apparu dans un des commentaires).
Base de C++14 solution est toujours manquant dans ce fil. EDIT: Non, c'est là la réponse de Walter.
Cette fonction est donnée:
Appeler avec le fragment de code suivant:
Exemple:
DÉMO
http://coliru.stacked-crooked.com/a/8ea8bcc878efc3cb
voulez-vous obtenir quelque chose comme ceci ici?
merci, j'ai 2 questions: 1. Pourquoi ne puis-je pas passer
std::make_unique
directement? Faut-il le béton en fonction de l'instance? 2. Pourquoistd::move(ts)...
si nous pouvons changer[](auto... ts)
à[](auto&&... ts)
?1. ne fonctionne pas à partir de la signature: votre
std::make_unique
s'attend à un n-uplet, et d'un n-uplet peut être créé à partir d'un déballé tuple uniquement par l'intermédiaire d'un autre appel àstd::make_tuple
. C'est ce que j'ai fait dans le lambda (même si c'est très redondant, comme vous pouvez aussi tout simplement copier le tuple dans le pointeur unique sans aucune utilisation pourcall
).2. Vous pourriez faire de la deuxième, mais je suppose que vous voulez travailler avec des copies ... il n'y a guère besoin de posséder pointeur de références. (Vous pouvez aussi l'obtenir avec votre deuxième version en utilisant quelque chose comme
std::make_tuple<std::decay_t<decltype(ts)...>>(std::forward<decltype(ts)>(ts) ...)
de retour, mais c'est beaucoup plus à écrire.)OriginalL'auteur davidhigh
C'est un peu compliqué à réaliser (même si c'est possible). Je vous conseille d'utiliser une bibliothèque où c'est déjà en œuvre, à savoir Coup de pouce.La Fusion (le invoquer fonction). Comme un bonus, Stimuler la Fusion est compatible avec le C++03 compilateurs.
OriginalL'auteur Karel Petranek
c++14 la solution. Tout d'abord, un utilitaire standard:
Ces vous permettent d'appeler un lambda avec une série de compilation des entiers.
et nous avons fini.
index_upto
etindex_over
vous permettent de travailler avec le paramètre packs sans avoir à générer un nouveau commissaire aux surcharges.Bien sûr, dans le c++17 vous venez de
Maintenant, si nous voulons que, dans le c++14 on peut écrire:
relativement facilement et obtenir le plus propre c++17 la syntaxe prêt à expédier.
il suffit de remplacer
notstd
avecstd
lors de votre compilateur mises à niveau et bob est votre oncle.std::apply
<- de la musique à mes oreillesSeulement un peu plus court que
index_upto
et moins souple. 😉 Essayez d'appelerfunc
avec les arguments en arrière avecindex_upto
etstd::apply
respectivement. Il est vrai, qui est le diable veut appeler une fonction à partir d'un n-uplet en arrière.Point mineur:
std::tuple_size_v
est le C++, 17, donc pour le C++14 solution qui aurait dû être remplacée partypename std::tuple_size<foo>::value
J'espère
value
n'est pas un type. Mais fixes de toute façon.Non, c'est
sizeof...(Types)
. J'aime votre solution sans letypename
.OriginalL'auteur Yakk - Adam Nevraumont
Réflexion sur le problème, certains plus, d'après la réponse donnée, j'ai trouvé un autre moyen de résoudre le même problème:
Qui nécessite une modification de la mise en œuvre de
delayed_dispatch()
:Cela fonctionne de manière récursive par la conversion de la
std::tuple
dans un paramètre pack dans son propre droit.call_or_recurse
est nécessaire comme une spécialisation de mettre fin à la récursivité avec le réel appel, qui déballe le formulaire de paramètre pack.Je ne suis pas sûr que c'est de toute façon une "meilleure" solution, mais c'est une autre façon de penser et de le résoudre.
Comme autre solution, vous pouvez utiliser
enable_if
, pour former quelque chose de sans doute plus simple que ma solution précédente:La première surcharge prend juste un argument de plus à partir de la n-uplet et le met dans un paramètre pack. La seconde surcharge prend un paramètre correspondant pack, puis fait le véritable appel, avec la première surcharge être désactivé dans le seul et unique cas où le second serait viable.
purement du point de vue apprentissage, je serais curieux de voir toutes les solutions de rechange qui ne se résument certains affreux hack avoir saboté le pointeur de pile (ou de la même convention d'appel astuces spécifiques).
OriginalL'auteur Flexo
Mon variation de la solution de Johannes utilisant le C++14 std::index_sequence (et le type de retour de fonction en tant que paramètre de modèle de RetT):
Je pense que les modèles a obtenu beaucoup mieux et plus compréhensible avec C++11 et 14. Il y A quelques années quand j'ai regardé ce boost avec des modèles sous le capot, je me suis vraiment découragé. Je suis d'accord que le développement de modèles est beaucoup plus difficile que de simplement les utiliser.
Tout d'abord, en termes de modèle de complexité, c'est rien. Deuxièmement, la plupart des aides modèles sont un investissement initial pour une tonne de gain de temps lors de l'instanciation d'eux plus tard. Enfin, quoi, vous serait plutôt pas ont la capacité de faire ce que les modèles vous permettent de le faire? Vous pourriez tout simplement pas l'utiliser, et ne pas laisser de commentaires non pertinents qui semblent être les services de police d'autres programmeurs.
OriginalL'auteur schwart