Das Erstellen und Bearbeiten von Zeichenfolgen während der Kompilierungszeit in C ++ bietet mehrere nützliche Anwendungen. Obwohl es möglich ist, Zeichenfolgen zur Kompilierungszeit in C ++ zu erstellen, ist der Prozess sehr umständlich, da die Zeichenfolge als variable Zeichenfolge deklariert werden muss, z
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Operationen wie die Verkettung von Zeichenfolgen, das Extrahieren von Teilzeichenfolgen und viele andere können einfach als Operationen für Zeichenfolgen implementiert werden. Ist es möglich, Zeichenfolgen zur Kompilierungszeit bequemer zu deklarieren? Wenn nicht, gibt es einen Vorschlag in den Arbeiten, der eine bequeme Deklaration von Zeichenfolgen zur Kompilierungszeit ermöglichen würde?
Warum bestehende Ansätze fehlschlagen
Im Idealfall möchten wir in der Lage sein, Zeichenfolgen zur Kompilierungszeit wie folgt zu deklarieren:
// Approach 1
using str1 = sequence<"Hello, world!">;
oder unter Verwendung benutzerdefinierter Literale
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
wo decltype(str2)
hätte ein constexpr
Konstruktor. Eine chaotischere Version von Ansatz 1 kann implementiert werden, wobei die Tatsache ausgenutzt wird, dass Sie Folgendes tun können:
template <unsigned Size, const char Array[Size]>
struct foo;
Das Array müsste jedoch über eine externe Verknüpfung verfügen. Damit Ansatz 1 funktioniert, müssten wir Folgendes schreiben:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Das ist natürlich sehr unpraktisch. Ansatz 2 ist eigentlich nicht umsetzbar. Wenn wir einen ( constexpr
) Literaloperator deklarieren würden, wie würden wir dann den Rückgabetyp angeben? Da der Operator eine variable Folge von Zeichen zurückgeben muss, müssten wir den const char*
Parameter verwenden, um den Rückgabetyp anzugeben:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
Dies führt zu einem Kompilierungsfehler, da s
es sich nicht um einen handelt constexpr
. Der Versuch, dies mit den folgenden Schritten zu umgehen, hilft nicht viel.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
Der Standard schreibt vor, dass diese spezielle Literaloperatorform für Ganzzahl- und Gleitkommatypen reserviert ist. Während 123_s
würde funktionieren, abc_s
würde nicht. Was ist, wenn wir benutzerdefinierte Literale ganz weglassen und nur eine reguläre constexpr
Funktion verwenden?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
Nach wie vor stoßen wir auf das Problem, dass das Array, jetzt ein Parameter für die constexpr
Funktion, selbst kein constexpr
Typ mehr ist .
Ich glaube, es sollte möglich sein, ein C-Präprozessor-Makro zu definieren, das eine Zeichenfolge und die Größe der Zeichenfolge als Argumente verwendet und eine Sequenz zurückgibt, die aus den Zeichen in der Zeichenfolge besteht (using BOOST_PP_FOR
, stringification, array subscripts und dergleichen). Ich habe jedoch nicht die Zeit (oder nicht genug Interesse), um ein solches Makro zu implementieren =)
constexpr
typisierte Vorlagenargumente unterteilt sind, können Sie sie in Funktionen verwenden und Arrays (daher concat, substr usw.) initialisieren.
constexpr
Zeichenfolgen können während der Kompilierungszeit analysiert werden, sodass Sie je nach Ergebnis unterschiedliche Codepfade verwenden können. Im Wesentlichen können Sie EDLs in C ++ erstellen. Die Anwendungen sind ziemlich grenzenlos.