6
votes

C ++ 11: Arguments de la fonction Variagene HOMODIC SANS-POD

Comment écririez-vous une fonction de modèle qui prend un nombre de variable d'arguments de fonction non-POD homogènes en C ++ 11?

Supposons que nous voulions écrire une fonction min pour tout type qui définit le moins que " opérateur <"comme suit: xxx

Ce qui précède est illégal C ++ 11, comment écrivez-vous légalement?


2 commentaires

Ce qui précède n'est pas illégal (en supposant que le ... s est juste une méthode pseudocode de dire "plus de choses ici").


@ R.martinhofernandes: je devine par le titre que ceux-ci ne sont pas pseudocode; L'OP a besoin d'arguments variables.


4 Réponses :


1
votes

C'est un peu compliqué mais c'est ce que vous obtenez si vous voulez Arguments hétérogènes: xxx

La première version est beaucoup plus intéressante cependant. common_type cherche le type que tous les arguments peuvent être contraints. C'est nécessaire car une fonction avec des arguments hétérogènes revenant L'un ou l'autre d'entre eux doit trouver ce type. Cependant, cela pourrait être contourné en utilisant boost :: variante mais pour les types intégrés, c'est plutôt inutile car ils doivent être contraints pour être comparé quand même.


5 commentaires

@Konradrudolph merci. Cela doit être résolu maintenant et les types de retour ainsi que les types d'arguments du foncteur doivent correspondre exactement aux types utilisés pour appeler min avec. Bien que je pense que cela gâche toujours des arguments mixtes de lvalue / rvalue, mais je ne sais pas comment résoudre ce problème. Quelque chose d'autre qui est toujours mal?


Je pense que dans ce cas, le meilleur recours est réellement de transmettre tous les arguments comme const Réf. Et si vous modifiez ou stockez les arguments, transmettez tout de valeur et espoir le meilleur.


@Konradrudolph mais qui empêcherait l'utilisation, telle que min (A, B) = 0 que je considérerais quelque peu utile.


Vrai mais même std :: min ne le permet pas.


@Konradrudolph Donc, ce que nous avons ici est un meilleur std :: min bien que à un certain coût.



10
votes

homogène? Utilisez simplement std :: initializer_list code> strong>. xxx pré>

(comme @ JESSE a noté, il s'agit de l'équivalent à std :: min dans la bibliothèque standard.) p>

Si vous n'aimez pas les accolades supplémentaires, faites un modèle variadique qui transmet la mise en œuvre de la liste d'initialistes: P>

template <typename... T>
auto min(T&&... args) -> decltype(min_impl({std::forward<T>(args)...}))
{
    return min_impl({std::forward<T>(args)...});
}

...

return min(8, 5, 1, 4, 6);


2 commentaires

C'est aussi la même chose que std :: min ) (peut-être qu'il devrait être a souligné que c'est un type de pod ou non ne fait pas une différence).


Il convient de noter que cela ne fonctionnera pas pour les types de déplacement uniquement. Vous ne pouvez pas sortir d'un initialiszer_list .



0
votes

Une autre possibilité:

template <typename T, typename... T2>
T min(T x1, T2... rest);

template <typename T>
T min(T x)
{
  return x;
}

template <typename T, typename... T2>
T min(T x1, T2... rest)
{
  return std::min (x1, min (rest...));
}


0 commentaires

4
votes

Premièrement, les modèles variadiques n'incluent pas un moyen de dire «un nombre variable d'arguments d'un seul type». Lorsque vous utilisez des modèles variadiques, vous obtenez un paquet de paramètres qui est un ensemble d'arguments zéro ou plus, chacun avec un type éventuellement unique: xxx

jeton A seulement a défini des significations pour ces packs de paramètres (et des fonctions Vararg, mais c'est à côté du point). Donc, vous ne pouvez pas l'utiliser avec des packs non paramètres: xxx p> second, une fois que vous avez un paquet de paramètres, vous ne pouvez pas simplement itérer sur les paramètres de la manière dont vous avez la façon dont vous avez la façon dont vous " Re montrant avec la boucle basée sur la plage. Au lieu de cela, vous devez écrire vos algorithmes dans un style fonctionnel, en utilisant l'expansion des paquets de paramètres aux paramètres «Épluchez» des paramètres du pack de paramètres. xxx

Bien que des modèles variadiques ne prennent pas en charge directement Ce que vous voulez, vous pouvez utiliser activer_if et utiliser la règle "Sfinae" pour imposer cette contrainte. D'abord voici une version qui sans la contrainte: xxx

puis appliquer activer_if Pour vous assurer que les types sont tous identiques. < Pré> xxx

La mise en œuvre modifiée ci-dessus empêchera la fonction d'être utilisée à tout moment, les arguments ne sont pas tous exactement les mêmes selon is_same .

Vous préférez probablement ne pas utiliser ces astuces si vous n'êtes pas obligé. Utiliser une initialisateur_List alors que KennyTM suggère est probablement une meilleure idée. En fait, si vous mettez vraiment en œuvre Min et max, vous pouvez vous épargner des problèmes car la bibliothèque standard comprend déjà des surcharges qui prennent une version initialisateur_list.


Comment est-ce document commun_type :: type> travail?

car il y a une seule version d'argument de min () la version variadique est sélectionnée uniquement quand il y a deux ou plusieurs paramètres. Cela signifie que taille de ... (US) est au moins un. Dans le cas où il est exactement un, common_type renvoie le type unique de type et is_same > assure que les deux types sont les mêmes.

L'implémentation variadique de min () appels min (US ...) . Tant que cet appel ne fonctionne que lorsque tous les types dans US ... sont les mêmes que nous savons que commont_type raconte ce que ce type est, et is_same > garantit que T est aussi ce même type.

Nous savons donc que min (A, B) < / Code> ne fonctionne que si A et B est le même type. Et nous savons que min (c, a, b) appels min (a, b) donc min (c, a, b) peut seulement être appelé si A et B est le même type et si C est également le même type. min (d, c, a, b) appels min (c, a, b) nous savons que min (d, c, a, b) ne peut être appelé que si c , A et b sont tous identiques et en outre si d < / code> est aussi le même type. C.


3 commentaires

Si vous exécutez que tous les types sont les mêmes, quelle est l'utilisation de common_type ? En outre, common_type == t peut être vrai sans tous types dans US ... étant identique à t .


@PMR Common_Type fait partie de la manière dont les types d'arguments sont forcés d'être les mêmes. Tous les types dans US ... seront les mêmes, de sorte que le type_TYPE sera ce type. Ceci est prouvé par induction.


@PMR J'ai ajouté un peu comment cette condition fonctionne pour que tous les types soient identiques.