2

Ich versuche, eine Kompilierzeit String-Klasse zu machen. Ich habe ein paar Hinweise von this post genommen. Unglücklicherweise bleibe ich bei der Überlastung des Konstruktors hängen: Der Konstruktor const char[] wird zugunsten des Konstruktors const char* ignoriert. Irgendwelche Tipps würden geschätzt!Kompilierzeichenfolgen: Konstruktorüberladung Vorrang zwischen 'const char * `/` const char [] `

Es gibt viele coole Dinge, die ich tun kann, wenn ich Compile-Time String-Konstanten machen kann.

  • Zeichenfolge Gleichheit Test ist schneller auf string als const char *
  • beseitigen Laufzeitaufwand von impliziten Konvertierungen const char *-string die strlen() auf Kompilierung-Konstante Strings nennen.
  • Compile-Zeit-String-Sets, die Gleichheit zu tun Prüfung statt für Größe < N. von Hashing (dies ist mehrere CPUs von Overhead auf eine Anwendung bei ich suche)
+0

Wenn man sich anschaut, [die 'std :: string' Konstruktorüberladungen] (http://en.cppreference.com/w/cpp/string/basic_string/basic_string) Sie werden sehen, dass sie es nicht tun Ärgere dich sogar mit Arrays, nur mit Zeigern. –

+1

Sie unterstützen auch nicht die Contexpr Konstruktion! Das ist der Punkt. Das templatierte Zeichenarray kann die Zeichenfolgengröße zur Kompilierzeit erkennen. –

+4

Nicht-templated Funktion hat eine Präferenz gegenüber Templates, auch wenn es Zeiger-Decay benötigt. Ich weiß nicht, wie ich das beheben soll. Ich hatte das selbe Problem selbst, als ich das versuchte, und entschied mich schließlich für Strings, die auf variablen Vorlagen basierten. – SergeyA

Antwort

1

Dies ist ein bisschen hässlich, aber es funktionieren soll:

template<class T, class = std::enable_if_t<std::is_same_v<T, char>>> 
string(const T * const & str) 
    : ptr_(str) { 
    length_ = strlen(str); 
} 

der Trick ist, dass der Zeiger durch const Referenzblocks Array-to-Zeiger Verfall bei Vorlage Argument Abzug nehmen, so dass, wenn Sie ein Array übergeben, kann der Compiler nicht T ableiten und der Konstruktor ist ignoriert.

Der Nachteil ist, dass dies auch andere Dinge ablehnen würde, die implizit in const char * umgewandelt werden können.


Eine Alternative könnte sein, alles umwandelbar const char *, zu akzeptieren, und dann mit der Absendung basiert, ob das Ding ein Array ist.

template<size_t N> 
constexpr string(const char(&char_array)[N], std::true_type) 
    : ptr_(char_array), length_(N-1) {} 

string(const char * str, std::false_type) 
    : ptr_(str) { 
    length_ = strlen(str); 
} 

template<class T, class = std::enable_if_t<std::is_convertible_v<T, const char *>>> 
constexpr string(T&& t) 
    : string(std::forward<T>(t), std::is_array<std::remove_reference_t<T>>()) {} 
+0

Beeindruckend. Ich habe etwas Ähnliches versucht, aber ohne den Pointer-Decay-Trick konnte es nicht funktionieren. +1 für die Erklärung, warum die 'const &' einen Unterschied macht. Unglücklicherweise glaube ich nicht, dass ich in der Lage sein werde, diesen Code-Review zu bekommen, da er den Vanilla-Code-Pfad kompliziert hat. –