Idéalement Déclarer au Moment de la Compilation des Chaînes en C++
Être en mesure de créer et de manipuler des chaînes de caractères lors de la compilation en C++ dispose de plusieurs applications utiles. Bien qu'il est possible de créer au moment de la compilation des chaînes en C++, le processus est très lourd, que la chaîne de caractères doit être déclaré comme un variadic séquence de caractères, par exemple:
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Des opérations telles que la concaténation de chaîne, sous-chaîne d'extraction, et beaucoup d'autres, peuvent être facilement mises en œuvre que les opérations sur les séquences de caractères. Est-il possible de déclarer au moment de la compilation des chaînes plus facilement? Si non, est-il une proposition dans les œuvres qui permettrait à la pratique de la déclaration de la compilation des chaînes?
Pourquoi Les Approches Existantes De L'Échec
Idéalement, nous aimerions être en mesure de déclarer au moment de la compilation des chaînes comme suit:
//Approach 1
using str1 = sequence<"Hello, world!">;
ou, à l'aide définis par l'utilisateur littéraux,
//Approach 2
constexpr auto str2 = "Hello, world!"_s;
où decltype(str2)
aurait un constexpr
constructeur. Une messier version de la méthode 1 est possible de mettre en œuvre, en tirant parti du fait que vous pouvez effectuer les opérations suivantes:
template <unsigned Size, const char Array[Size]>
struct foo;
Toutefois, le tableau aurait besoin d'avoir une liaison externe, afin d'obtenir de 1 à travailler, vous devez écrire quelque chose comme ceci:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Inutile de dire que cela est très gênant. Approche 2 est en fait pas possible de mettre en œuvre. Si nous étions à déclarer (constexpr
) littérale de l'opérateur, alors comment pourrions-nous préciser le type de retour? Depuis que nous avons besoin l'opérateur pour retourner un variadic séquence de caractères, de sorte que nous aurions besoin d'utiliser le const char*
paramètre pour spécifier le type de retour:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Il en résulte une erreur de compilation, car s
n'est pas un constexpr
. En essayant de contourner ce problème en procédant de la manière suivante n'aide pas beaucoup.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
La norme veut que ce spécifique littérale de l'opérateur formulaire est réservé pour l'entier et les types à virgule flottante. Alors que 123_s
, la abc_s
ne le serait pas. Si nous fossé définis par l'utilisateur littéraux tout à fait, et juste utiliser un constexpr
fonction?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Comme avant, nous rencontrons le problème est que le tableau, maintenant un paramètre à la constexpr
fonction, est en lui-même n'est plus un constexpr
type.
Je crois qu'il devrait être possible de définir un préprocesseur C macro qui prend une chaîne de caractères et la taille de la chaîne en argument, et renvoie une séquence comprenant les caractères dans la chaîne (à l'aide de BOOST_PP_FOR
, stringification, tableau des indices, etc). Cependant, je n'ai pas le temps (ou suffisamment d'intérêt) pour mettre en œuvre une telle macro =)
- Boost est une macro qui définit une chaîne de caractères qui peut être utilisé comme une expression constante. Eh bien, il définit une classe qui a un membre de type string. Avez-vous vérifier cela?
- Liaison externe n'est pas une exigence de plus pour les non-gabarit de type d'arguments. En fait,
str
a une liaison interne dans votre exemple. (Point mineur, vous ne pouvez toujours pas utiliser les littéraux de chaîne.) - Avez-vous vérifié cpp-next.com/archive/2012/10/... ?
- Un Débordement de pile n'est pas l'endroit approprié pour poser de savoir si une proposition pour quelque chose existe. Le meilleur endroit pour ce faire pourrait être la le C++ du site.
- Ah, donc la mise en œuvre de cette aide du préprocesseur est plus facile que je ne le pensais. Voulez-vous post que comme la réponse? Abrahams solution semble élégante pour moi.
- Ce que je voulais dire est un peu différente de ce que le titre implicite. Maintenant j'ai édité le titre et le corps afin de réfléchir à ma question avec plus de précision. Si aucune méthode n'existe en C++11 pratique pour initialiser au moment de la compilation des chaînes, alors oui, je me demandais si il y a une proposition dans les œuvres. Cependant, Evgeny Panasyuk a souligné un article de David Abrahams qui donne une solution élégante. Donc, je pense que cette question peut toujours être utile à d'autres personnes qui sont à la recherche pour plus d'informations sur la compilation des chaînes de caractères.
- Avez-vous vraiment besoin de simples caractères non-type de modèle arguments? Vous pouvez envisager d'utiliser constexpr tableaux, voir par exemple ce DONC, la question, Xeo (et ma) réponse
- Je pense que j'ai besoin de l'caractères non-gabarit de type d'arguments. Corrigez-moi si je me trompe, mais une fois que les deux
std::array
s ont été renvoyées de laconstexpr
fonction dans Xeo réponse, ils ne peuvent plus être concaténés au cours de la compilation. Je voudrais la capacité de manipuler des chaînes de caractères lors de la compilation (par exemple, la concaténation de chaîne d'extraction, etc.), après qu'ils ont été initialisés. - Qu'est ce que le DONC, la question que j'ai mentionné est tout au sujet de: la Concaténation de chaînes au moment de la compilation. Voir aussi cette bibliothèque pour le moment de la compilation de manipulation de chaîne; je pense que j'ai même vu une plus amélioré la bibliothèque (il ne peut pas trouver un guichet automatique).
- Fondamentalement, vous développez les caractères stockés dans le tableau/pointeur en paramètre pack (comme Xeo n'). S'ils ne sont pas divisés en non-type de modèle arguments, vous pouvez les utiliser dans
constexpr
fonctions et d'initialiser les tableaux (donc, concat, substr, etc). - Intéressant, donc le membre de la pile dans le
constexpr
classe string peut être utilisé dans la suiteconstexpr
consolidés. Je vais jouer avec cela, et de voir comment les deux implémentations de comparer. À l'aide de tableaux au lieu de variadic séquences dechar
peut rendre les choses plus faciles. - Où voulez-vous? Quelle est la différence entre celui-ci et const char* / string pour votre cas d'utilisation?
- En bref,
constexpr
des chaînes peut être analysé au cours de la compilation, de sorte que vous pouvez prendre différents chemins de code en fonction des résultats. Essentiellement, vous pouvez créer des listes de montage en C++; les applications sont assez infinies.
Vous devez vous connecter pour publier un commentaire.
Je n'ai rien vu de match de l'élégance de Scott Schurr de
str_const
présenté à C++ Maintenant En 2012. Il ne nécessiteconstexpr
bien.Voici comment vous pouvez l'utiliser, et ce qu'il peut faire:
Il ne va pas beaucoup plus frais qu'au moment de la compilation le contrôle de la portée!
À la fois l'utilisation et la mise en œuvre, est libre de macros. Et il n'y a pas de limite artificielle sur la taille de la chaîne. J'ai poster la mise en œuvre ici, mais je suis en respectant Scott implicite du droit d'auteur. La mise en œuvre est sur une seule diapositive de sa présentation lié ci-dessus.
StrWrap
et Scottstr_const
sont presque identiques.str_const
et l'autre basée sursequence
), cela peut être possible. L'utilisateur devrait utiliserstr_const
pour initialiser la chaîne, mais la suite des opérations de créer de nouvelles chaînes serait de retoursequence
objets.str_const
). Constexpr peut être utilisé pour créer presque tout ce que vous voulez, tant que vous comprenez les règles.constexpr
opérations pour les chaînes., mais je n'ai pas eu beaucoup de chance d'utiliser l'une d'elles pourtant.template<char... cs>
. En théorie, on pourrait construire quelque chose qui prend une chaîne littérale et compile le contenu d'une fonction. Voir la réponse par la dpj. Un très complète-à la recherche de la bibliothèque est metaparse. Essentiellement, vous pouvez définir la cartographie des chaînes de caractères littérales de types, et de la mettre en œuvre avec ce type de technologie.?raw=true
permet au moins de lire les PDF).constexpr operator==
. Désolé. Scott présentation devrait vous obtenir a commencé sur la façon de le faire. Il est beaucoup plus facile en C++14 qu'en C++11. Je n'aurais même pas la peine d'essayer en C++11. Voir Scott dernièreconstexpr
parle ici: youtube.com/user/CppConconststr
vient d'ici: en.cppreference.com/w/cpp/language/constexpr Il le dit dans son PDF (page 72). Il a fait quelques changements, mais il est toujours très proche. Il n'y a pas de nom d'auteur sur le C++ page de Référence, bien que.il est possible de mettre en œuvre ce sans compter sur un coup de pouce, en utilisant très simple macro et certains de C++11 caractéristiques:
(les deux derniers ne sont pas strictement nécessaires ici)
nous avons besoin pour être en mesure d'instancier un variadic template avec de l'utilisateur fourni indicies de 0 à N - un outil aussi utile par exemple pour développer un tuple dans variadic template fonction de l'argument (voir questions: Comment puis-je développer un tuple dans variadic template de la fonction d'arguments?
"déballage" un tuple pour appeler un correspondant pointeur de fonction)
puis de définir une variadic template appelé chaîne avec des non-type de
paramètre char:
maintenant la partie la plus intéressante - pour transmettre des chaînes de caractères dans la chaîne
modèle:
une simple concaténation de démonstration illustre l'utilisation:
https://ideone.com/8Ft2xu
operator+
au lieu deoperator*
?(str_hello + str_world)
CSTRING
macro. Sinon, vous ne pouvez pas créer unCSTRING
à l'intérieur d'un appel vers un[]
opérateur, double[[
sont réservés pour les attributs.CSTRING
macro dans un modèle de classe, vous devez ajouter untypename
entrereturn
etvariadic_toolbox...
et untemplate
avantproduce
. Voir mon 2ème réponse ci-dessous un copier-coller des prêts à la version contenant les correctifs à partir de deux de mes commentaires.Edit: comme Howard Hinnant (et moi un peu dans mon commentaire à l'OP) a souligné, vous ne pourriez pas besoin d'un type à chaque caractère de la chaîne comme un seul argument de modèle.
Si vous avez besoin de ce, il y a une macro-gratuit solution ci-dessous.
Il y a un truc que j'ai trouvé tout en essayant de travailler avec des chaînes au moment de la compilation. Il nécessite d'introduire un autre type d'ailleurs la "chaîne de modèle", mais à l'intérieur des fonctions, vous pouvez limiter la portée de ce type.
Ils n'utilisent pas de macros, mais plutôt un peu de C++11 caractéristiques.
pair<int,pair<char,double>>
. J'étais fière de moi, puis découvert cette réponse, et le metaparse de la bibliothèque aujourd'hui! Je devrais vraiment une recherche plus approfondie avant de commencer des projets ridicules comme ça 🙂 je suppose que, en théorie, un compilateur C++ pourrait être construit à partir de ce type de technologie. Quelle est la chose la plus folle qui a été construit avec cela?char[]
.my_str.print();
au lieu destr.print();
?Si vous ne souhaitez pas utiliser le Stimuler la solution vous pouvez créer des macros simples qui permettront de faire quelque chose de similaire:
Le seul problème est la taille fixe de 64 caractères (plus le zéro). Mais il peut facilement être modifié en fonction de vos besoins.
sizeof(str) > i
(au lieu de l'ajout de la supplémentaire0,
jetons)? Il est facile de définir untrim
metafunction qui va le faire après la macro a déjà été appelé, mais il serait bien si la macro elle-même peut être modifié.sizeof(str)
. Il est possible d'ajouter manuellement de la taille de la chaîne commeMACRO_GET_STR(6, "Hello")
mais cela nécessite de Stimuler les macros de travailler en raison de l'écrire manuellement besoin de 100 fois plus de code (vous avez besoin d'implémente chose simple comme1+1
).Il y a de l'article: Utiliser des chaînes de caractères en C++ template metaprograms par Abel Sinkovics et Dave Abrahams.
Il a une certaine amélioration par rapport à votre idée de l'utilisation de macro + BOOST_PP_REPEAT - il ne nécessite pas de passage explicite de la taille de la macro. En bref, il est basé sur fixe la limite supérieure pour la taille de la chaîne et de la "chaîne de dépassement de protection":
plus conditionnelle boost::mpl::push_back.
Si vous acceptez les zéros à droite, écrite à la main macro en boucle, 2x repetion de la chaîne d'élargissement de la macro, et n'ont pas de Boost, alors je suis d'accord - c'est mieux. Cependant, avec le Boost, il serait juste trois lignes:
DÉMO
Voici un bref C++14 solution pour créer un std::tuple<char...> pour chaque moment de la compilation chaîne de caractères passée.
Et voici une pour la création d'un unique type de compilation, tronquée en bas de la macro autre post.
C'est vraiment dommage que définis par l'utilisateur littéraux ne peut pas être utilisé pour cette encore.
Un collègue m'a défié de concaténer des chaînes de caractères dans la mémoire au moment de la compilation. Il comprend l'instanciation de chaînes individuelles au moment de la compilation ainsi. Le code complet d'inscription est ici:
objdump -t a.out |grep my
ne trouve rien. Quand j'ai commencé à taper ce code j'ai continué à expérimenter avec la suppression deconstexpr
les fonctions et lesobjdump
leur a montré lors de laconstexpr
a été omis. Je suis à 99,9% sûr de soi, il arrive au moment de la compilation.-S
), vous remarquerez que gcc (4.7.2) n'a en effet résoudre leconstexpr
fonctions au moment de la compilation. Pourtant, les cordes sont pas assemblés au moment de la compilation. Plutôt, (si j'interprète correctement) pour chaque char de ces "montées" à cordes, il y a unmovb
opération, qui est sans doute l'optimisation que vous recherchez.Personne ne semble aimer mon autre réponse :-<. Donc ici, je montre comment convertir un str_const à un type réel:
Compile avec clang++ -stdlib=libc++ -std=c++14 (clang 3.7)
basé sur l'idée de Howard Hinnant vous pouvez créer littérale de la classe qui va ajouter deux littéraux ensemble.
str_at
en venir?str_at<int I>(const char* a) { return a[i]; }
kacey la solution pour la création d'un unique type de compilation peut, avec de légères modifications, également être utilisé avec C++11:
Utilisation:
Tout en jouant avec le coup de pouce hana carte, je suis tombé sur ce thread. Non des réponses résolu mon problème, j'ai trouvé une autre solution qui je veux ajouter ici qu'il pourrait être potentiellement utile pour les autres.
Mon problème est que lors de l'utilisation du boost hana carte avec hana chaînes, le compilateur a généré certains d'exécution du code (voir ci-dessous). La raison en est évidemment que, à la requête de la carte au moment de la compilation, il doit être
constexpr
. Ce n'est pas possible puisque leBOOST_HANA_STRING
macro génère un lambda, qui ne peut pas être utilisé dansconstexpr
contexte. D'autre part, la carte des besoins des chaînes de caractères avec un contenu différent à être de différents types.Que les solutions dans ce fil sont soit à l'aide d'un lambda ou de ne pas fournir différents types de contenu différent, j'ai trouvé l'approche suivante utiles. Aussi, il évite le hacky
str<'a', 'b', 'c'>
de la syntaxe.L'idée de base est d'avoir une version de Scott Schurr de
str_const
modélisé sur la table de hachage des personnages. Il estc++14
, maisc++11
devrait être possible avec un appel récursif à la mise en œuvre de lacrc32
fonction (voir ici).Utilisation:
Résultant du code assembleur avec
clang-cl
5.0 est:Votre approche #1 est la bonne.
Non, pas correct. Cette compile avec clang et de la gcc. J'espère que son standard c++11, mais je ne suis pas un langage de juriste.
Ce que je voudrais vraiment de l'amour pour le c++17 serait l'équivalent (à compléter l'approche #1)
Quelque chose de très similaire existe déjà dans la norme basé sur un modèle défini par l'utilisateur littéraux,les vides pointeur mentionne également, mais uniquement pour les chiffres.
Jusqu'alors, une autre astuce consiste à utiliser le correcteur de mode d'édition + copier-coller de
Si vous n'avez pas l'esprit de la macro, que cela fonctionne(légèrement modifié de Yankes réponse):
Je voudrais ajouter deux très petites améliorations pour le réponse de @user1115339. Je l'ai mentionné dans les commentaires pour la réponse, mais pour des raisons de commodité, je vais mettre un copier coller de la solution ici.
La seule différence est la
FIXED_CSTRING
macro, qui permet d'utiliser des chaînes dans les modèles de classe et que les arguments de l'opérateur index (utile si vous avez par exemple une compile-time de la carte).Live exemple.
Ma propre mise en œuvre est basée sur une approche de l'
Boost.Hana
chaîne (modèle de classe avec variadic caractères), mais utilise seulement lesC++11
standard etconstexpr
fonctions avec contrôle strict sur compiletimeness (ce serait une erreur de compilation si ce n'est un moment de la compilation de l'expression). Peut être construit à partir de l'habituel raw chaîne C au lieu de la fantaisie{'a', 'b', 'c' }
(par le biais d'une macro).Mise en œuvre:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/include/tacklelib/tackle/tmpl_string.hpp
Tests:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/src/tests/unit/test_tmpl_string.cpp
Exemples d'utilisation:
Les détails sur un
constexpr
fonction de la compilation de la frontière: https://www.boost.org/doc/libs/1_65_0/libs/hana/doc/html/index.html#tutorial-appendix-constexprPour d'autres détails d'utilisation voir les tests.
L'ensemble du projet est actuellement à l'expérimentation.