2

Ich versuche, ausgefallene Spiele zu spielen, bei denen der C++ - Compiler Hash-Werte von konstanten Strings bei Compiletime synthetisiert. Dadurch könnte ich die Zeichenfolge durch eine einzige Kennung ersetzen, wodurch sich die Codegröße und Komplexität erheblich verringert.Ist ein Compiletime-Konstanten-Index in ein Compiletime-Konstanten-Array selbst Compiletime-Konstante?

Für Programmierung Klarheit und Leichtigkeit, es wäre genial, wenn ich Compiletime mit einfachen Inline-Zeichenfolgen wie "Hallo", die Compiletime konstante Zeiger auf Compiletime Konstante Zeichen sind untersuchen und berechnen.

Wenn ich in diese bei compiletime indizieren kann, kann ich ein Template-Metaprogramm machen, um zu tun, was ich will. Es ist jedoch unklar, ob der C++ - Standard einen ct-konstanten Index eines ct-Konstanten-Arrays selbst als ct-Konstante behandelt.

eine andere Art und Weise, ist

gestellte
const char v="Hello"[0]; 

ganz gültig C++ (und C). Aber ist der Wert v eine Kompilierzeitkonstante?

Ich glaube schon, die Antwort ist nein, aber in der Praxis akzeptieren einige Compiler es ohne jede Warnung, viel weniger Fehler. Zum Beispiel können die folgenden kompiliert und ausgeführt, ohne auch nur eine einzige Warnung von Intel C++ Compiler:

#include <iostream> 
const char value="Hello"[0]; 
template<char c> void printMe() 
{ 
    std::cout << "Template Val=" << c << std::endl; 
} 

int main() 
{ 
    const char v='H'; 
    printMe<'H'>(); 
    printMe<v>(); 
    printMe<value>(); // The tricky and interesting case! 
} 

jedoch Microsofts Compiler überhaupt nicht kompilieren, eine einigermaßen zusammenhängende Fehlermeldung über die Verwendung einer Vorlage mit einem Objekt mit internen geben Verknüpfung.

Ich vermute die Antwort auf meine Frage ist "Nein, Sie können keine Array-Referenz selbst auf ein konstantes Array mit einem konstanten Index ist konstant bei Compiletime annehmen". Bedeutet das, dass die erfolgreiche Ausführung des Intel-Compilers ein Fehler im Intel-Compiler ist?

Antwort

2

Es funktioniert auch nicht auf GCC.

Allerdings, außerhalb einer Sprache-Compliance-Sichtweise, es ist schön, dass der Compiler-Optimierer behandelt es als eine Zeichenkonstante, so ziemlich. Ich habe diese Tatsache ausgenutzt, um Präprozessor-generierte Charakterkonstanten zuzulassen (mit *#foo). Siehe http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=1652, in der Datei hdr.h. Mit diesem Makro können Sie

DECR(h, e, l, l, o) 

statt

DECR('h', 'e', 'l', 'l', 'o') 

viel besser lesbar, aus meiner Sicht schreiben. :-)

+0

Clever Makro Hack den stringize Makro Operator verwenden rohe Zeichen Charize! Natürlich hilft das nicht viel, wenn man versucht, ein Template-Argument zu verwenden. Es sei denn, vielleicht könnte ein varargs style Makro (C99 ??) ein char entfernen, einen neuen typedef erstellen und die verbleibenden var args als rekursiven Typ a-la Loki? – SPWorley

1

Gute Frage, ja dies getan werden kann, und seine feine mit den Standards, und es wird auf Microsoft, GCC zu arbeiten, und Intel, Problem ist, dass Sie die Syntax falsch haben :)

One zweitens werde ich ein probe kochen ... Ok fertig, hier ist es. Dieses Beispiel ist gültig C++, und ich habe es ziemlich oft verwendet, aber in der Tat wissen die meisten Programmierer nicht, wie man es richtig macht.

template<char* MSG> 
class PrintMe 
{ 
public: 
    void operator()() 
    { 
     printf(MSG); 
    } 
}; 

char MyMessage[6] = "Hello"; //you can't use a char*, but a char array is statically safe and determined at compiletime 

int main(int argc, char* argv[]) 
{ 
    PrintMe<MyMessage> printer; 
    printer(); 
    return 0; 
} 
+1

Dies ist nicht Zugriff auf die Daten bei Compiletime, nur der Char-Zeiger. So zum Beispiel nach dem Drucker(); Anruf Sie können MyMessage hinzufügen [0] ++; Drucker(); und Sie werden die Daten aktualisiert sehen. Dies bedeutet, dass auf die Daten zur Laufzeit zugegriffen wird, nicht auf Kompilierungszeit. Aber Ihr Beispiel ist immer noch interessant, weil ein nicht-konstanter Zeiger als Template-Argument übergeben werden kann. – SPWorley

+0

Das heißt, ich bin mir nicht sicher, was Sie tun wollten, aber wenn ich das oben tun kann, können Sie vielleicht tun, was Sie wollen, können Sie eine bessere Erklärung für das erwartete Verhalten Ihrer letzten Vorlage geben? –

+0

Ok, jetzt denke ich, dass ich es verstehe, aber nein, du kannst es nicht tun. Da hängt es unter anderem auch von der Endianz der Hardware ab –

0

Der relevante Unterschied hier ist der Unterschied zwischen einem "Integral Constant Expression" und einer reinen Kompilierzeitkonstante. "3.0" ist eine Kompilierzeitkonstante. "int (3.0)" ist ebenfalls eine Kompilierzeitkonstante. Aber nur "3" ist ein ICE. [Siehe 5.19]

More details at boost.org

+0

Danke für die Referenz, aber es scheint nicht zutreffen. Im Beispielcode const char value = "Hello" [0]; Definiert den Wert als einen konstanten Ausdruck (wie die Boost-Seite als Beispiel 3 zeigt). Der Wert wird jedoch als Vorlageargument zurückgewiesen. Daher sind Integral Constant Expressions keine Kompilierzeitkonstanten, die in Vorlagen verwendet werden können. – SPWorley

+0

Guter Punkt, aber nicht relevant. Eine globale Konstante vom Integer-Typ ist genau dann ein ICE, wenn sie mit einem ICE selbst initialisiert wird. Zum Beispiel const char value = rand(); ist auch kein ICE, aber es sieht auch wie Beispiel 3 von Boost aus. Ihr Problem ist das gleiche, "Hallo" [0] ist kein ICE, deshalb können Sie andere ICEs damit nicht initialisieren. – MSalters

Verwandte Themen