J'aimerais transmettre une liste de manipulateurs à une fonction, quelque chose comme ceci: qui serait idéalement appelé par code quelque chose comme ceci: p> error: âconst _Tp* __gnu_cxx::new_allocator< <template-parameter-1-1>
>::address(__gnu_cxx::new_allocator< <template-parameter-1-1> >::const_reference)
const [with _Tp = std::ios_base&(std::ios_base&); __gnu_cxx::new_allocator<
<template-parameter-1-1> >::const_pointer = std::ios_base& (*)(std::ios_base&);
__gnu_cxx::new_allocator< <template-parameter-1-1> >::const_reference =
std::ios_base& (&)(std::ios_base&)]â cannot be overloaded
4 Réponses :
Étant donné que les manipulateurs sont des fonctions, cela dépend de leur signature. Cela signifie que vous pouvez créer du vecteur de manipulateurs avec la même signature.
Par exemple: P>
#include <iomanip> #include <vector> #include <iostream> #include <functional> typedef std::function< std::ios_base& ( std::ios_base& ) > manipF; std::vector< manipF > getManipulators() { std::vector< manipF > m = { std::showpos, std::boolalpha, [] ( std::ios_base& )->std::ios_base& { std::cout << std::setprecision( 2 ); return std::cout; } }; return m; } int main() { auto m = getManipulators(); for ( auto& it : m ) { it(std::cout); } std::cout<<"hi " << true << 5.55555f << std::endl; }
Votre SetPrecision Code> Lambda utilise STD :: Cout, mais pas le paramètre donné. Je suppose que c'est parce que
SetPreCision code> est défini en termes de flux
basic_ [io] code>. Sinon, j'aime votre approche +1
Vos manipulateurs peuvent avoir à peu près des types arbitraires. Vous devez donc utiliser des modèles pour les gérer. Afin d'y accéder en utilisant un pointeur ou une référence de type fixe, vous devrez utiliser une classe de base commune pour tous ces modèles. Ce type de polymorphisme ne fonctionne que pour les pointeurs et les références, mais vous voulez probablement une sémantique de valeur, en particulier pour les stocker dans des conteneurs. Donc, le moyen le plus simple consiste à laisser un Le résultat pourrait ressembler à ceci: p> < Pré> xxx pré> avec ceci, votre code fonctionne après de légères modifications apportées aux espaces de noms: p> partagé_ptr code> prendre en charge la gestion de la mémoire et en utilisant une autre classe pour masquer tous les détails laids de l'utilisateur.
J'ai essayé à la fois la réponse acceptée et cela. Celui-ci fonctionne mieux, IMHO: les manipulateurs peuvent être stockés dans des vecteurs et les vecteurs de manipulateurs peuvent être stockés et transmis. Pour une raison quelconque, la réponse acceptée ne le permet pas.
Un manipulateur de sortie est simplement n'importe quel type pour lequel os << m code> est défini pour certains
basic_ostream code> instanciation. Un manipulateur peut être une fonction (sous réserve de l'opérateur
<<< / code> des surcharges de
basic_ostream code>) mais il peut également être n'importe quel type qui définit son propre opérateur
<<< / code>. En tant que tel, nous avons besoin d'effectuer une effacement de type pour capturer l'opérateur
<<< / code> pour un
approprié (code> basic_ostream code> instanciation; Le moyen le plus simple de le faire est avec
std :: fonction code> et une lambda:
Approche intéressante, mais ne compile pas avec G ++ - 4.7.
@Oolafdietsche Clang-3.2 va bien; On dirait un bug avec la manipulation de G ++ de références universelles aux fonctions. Je vais voir si je peux trouver une solution de contournement.
@Oolafdietsche J'ai ajouté une surcharge pour g ++; Cela fonctionne maintenant avec G ++ - 4.7.2.
Merci! Merveilleusement simple et simple de le faire.
Solution C ++ Standard 17, pourrait être basée sur STD :: Tuple. Voici le POC
int main() { // quick p.o.c. auto ios_mask_keeper = [&](auto mask) { // keep tuple here static auto mask_ = mask; return mask_; }; // make required ios mask and keep it auto the_tuple = ios_mask_keeper( // please note we can mix ios formaters and iomanip-ulators std::make_tuple(std::boolalpha, std::fixed, std::setprecision(2) ) ); // apply iomanip's stored in a tuple std::apply([&](auto & ...x) { // c++17 fold (std::cout << ... << x); }, the_tuple); return 0;
Les manipulateurs sont souvent des fonctions. Il n'y a donc pas de classe de base commune pour eux.
Vous pouvez simplement définir vos propres cours d'emballage avec un flux opérateur qui applique le manipulateur et une base commune et l'utiliser pour votre paramètre?
Si vous voulez vraiment faire cela, vous devez probablement écrire votre fonction sous forme de modèle variadique (car différents manipulateurs ont des types différents, dont la plupart que vous ne connaissez pas). Même avec cela, cela ne sera pas trivial (par exemple, vous devrez probablement utiliser
std :: lid code> pour gérer des manipulateurs qui prennent des arguments).
@Jerrycoffin Je pense qu'un modèle de fonction variadique fonctionnerait également.
@Angew: Je pensais que c'était ce que j'ai dit. C'est ce que je voulais dire, de toute façon ...
@Jerrycoffin Je crois que votre commentaire original a déclaré "Macro".
@Angew: hmm ... j'espère que non. Je suppose qu'une macro pourrait fonctionner aussi, mais ce n'est certainement pas ce que je conseillerais.
@JmetCalfe, après avoir écrit ma propre réponse, je vois maintenant que votre commentaire mentionne déjà les principaux ingrédients que j'ai utilisés. Alors oui, cela peut être fait pour travailler.