“la chaîne de l'interpolation” en C++: la Construction d'un std::string avec les valeurs intrinsèques (par exemple, pour les messages d'erreur)?
Je veux créer une chaîne avec des informations intégrées. Un moyen (pas la seule) de la réalisation de ce que je veux, c'est appelé chaîne d'interpolation ou la substitution de variable, où les espaces dans une chaîne de caractères sont remplacés par des valeurs réelles.
En C, je voudrais faire quelque chose comme ceci:
printf("error! value was %d but I expected %d",actualValue,expectedValue)
alors que si je ont été de programmation en python, je voudrais faire quelque chose comme ceci:
"error! value was {0} but I expected {1}".format(actualValue,expectedValue)
ces deux sont des exemples de chaîne d'interpolation.
Comment puis-je le faire en C++?
Mises En Garde Importantes:
- Je sais que je peux utiliser
std::cout
si je veux imprimer un message sur la sortie standard (pas de chaîne d'interpolation, mais affiche le type de chaîne que je veux):
cout << "error! value was " << actualValue << " but I expected "
<< expectedValue;
Je ne veux pas impression une chaîne de caractères sur la sortie standard stdout. Je veux passer un std::string
comme argument à une fonction (par exemple, le constructeur d'un objet d'exception).
- Je suis à l'aide de C++11, mais la portabilité est potentiellement un problème, en connaissant les méthodes qui fonctionne et ne fonctionne pas dans les versions de C++ serait un plus.
Modifier
- Pour ma immédiat de l'usage, je ne suis pas préoccupé par la performance (je suis le déclenchement d'une exception pour cryin' out loud!). Cependant, sachant que la performance relative des différentes méthodes serait très très utile en général.
- Pourquoi ne pas simplement utiliser printf lui-même (C++ est un sur-ensemble de C, après tout...)? Cette réponse traite certaines raisons, pourquoi pas. Aussi loin que je peux comprendre, le type de sécurité est une grande raison: si vous placez %d, la variable que vous avez mis en il y avait de mieux vraiment être convertibles en un nombre entier, comme c'est la fonction des chiffres de quel type il est. Il serait beaucoup plus sûr d'avoir une méthode qui utilise au moment de la compilation de connaissances du type réel de l'variables à insérer.
Qu'en est seulement à l'aide de
printf
ou fprintf(std::cout, ...
dans c++
?Stroustrupp met ensemble un bel exemple de l'utilisation de variadic template avec des fonctions de type sécurisé printf. En fait je pense que c'est une bonne mise en œuvre.
c'est une excellente question. J'ai ajouté une note sur ce sujet.
Ceci est appelé la chaîne d'interpolation, par la manière.
OriginalL'auteur stochastic | 2016-06-21
Vous devez vous connecter pour publier un commentaire.
Méthode 1: à l'Aide d'une chaîne de stream
Il ressemble
std::stringstream
donne une solution rapide:Positif
Négatif
Méthode 2: Boost Format
La Boost Format bibliothèque est également une possibilité. En utilisant cela, vous feriez:
Positif
Négatif
Edit:
Méthode 3: variadic template parameters
Il semble qu'un type sûr de la version de printf peuvent être créés en utilisant variadic template parameters " (le terme technique pour un modèle qui prend un nombre indéterminé de paramètres du modèle). J'ai vu un certain nombre de possibilités dans cette veine:
Positif
Négatif
C'est un bon point, si l'on peut prétendre que le second moyen n'est pas vraiment plus facile à rechercher. Lorsque l'on regarde un message d'erreur comme ça, j'aurais tendance à la recherche de ce qui ressemble à la constante de pièces de toute façon (c'est à dire que j'avais de la recherche pour "erreur! valeur", ou "mais je m'y attendais"). Idéalement, le message d'erreur lui-même aurait une certaine leader unique chose qui pourrait être recherché (par exemple, "erreur #5:"), mais c'est une question de comment les erreurs sont structurés...
langues" comme dans la vraie langues qui ne sont pas des langages de programmation.
référence du péché" donne de meilleurs résultats qu'un simple "Undefined reference", donc ça dépend. Par les langues, je veux dire les langues humaines. Certaines langues peuvent avoir besoin de différents ordre des paramètres de ne pas sonner comme Yoda. Certains peuvent avoir besoin d'une ponctuation après le dernier paramètre.
Oui, de son mieux pour localiser l'ensemble de la chaîne dans son ensemble. Une alternative à l'utilisation de
boost::format()
serait tout simplementstd::string::replace()
pour remplir les espaces réservés, par exemple:std::string s = "error! value was %1% but I expected %2%"; std::string::size_type idx = s.find("%1%"); s.replace(idx, 3, std::to_string(acutalValue)); idx = s.find("%2%"); s.replace(idx, 3,std::to_string(expectedValue)); throw MyException(s);
Pas aussi élégant queboost::format()
, ou mêmestd::stringstream
, mais encore utilisable dans les cas simples.OriginalL'auteur stochastic
En C++11, vous pouvez utiliser
std::to_string
:C'est pas joli, mais c'est simple, et vous pouvez utiliser une macro pour le rétrécir un peu. La Performance n'est pas idéal, puisque vous n'avez pas
reserve()
de l'espace à l'avance. Variadic templates serait probablement plus rapide et esthétique.Ce genre de chaîne de construction (au lieu de l'interpolation) est aussi mauvais pour la localisation, mais vous devriez probablement utiliser une bibliothèque si vous avez besoin.
OriginalL'auteur Peter Tseng
Utilisez ce que vous voulez:
1) std::stringstream
2) libfmt : https://github.com/fmtlib/fmt
OriginalL'auteur Vyacheslav Napadovsky