2012-11-20 16 views
12

Gibt es eine Möglichkeit, den Wert eines constexpr oder #define d Wert zur Kompilierzeit zu drucken? Ich möchte das Äquivalent von std::cout << oder irgendeine Art und Weise wie Bearbeiten etwasstd :: cout entspricht zur Kompilierzeit, oder static_assert stringification der Kompilierzeitkonstante Werte in C++ 11

constexpr int PI_INT = 4; 
static_assert(PI_INT == 3, 
       const_str_join("PI_INT must be 3, not ", const_int_to_str(PI_INT))); 

zu tun: Ich kann einige grundlegende Compile-Zeit zu tun mit constexpr s Druck, zumindest auf gcc durch so etwas wie

tun
template <int v> 
struct display_non_zero_int_value; 

template <> 
struct display_non_zero_int_value<0> { static constexpr bool foo = true; }; 

static constexpr int v = 1; 

static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0"); 

was gibt mir error: incomplete type ‘display_non_zero_int_value<1>’ used in nested name specifier static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0");. (Icpc, auf der anderen Seite, ist wenig hilfreich, und sagt nur error: incomplete type is not allowed) Gibt es eine Möglichkeit, einen Makro zu schreiben, die diese verallgemeinern können, so dass ich so etwas wie

constexpr int PI_INT = 4; 
PRINT_VALUE(PI_INT) 

tun kann, und eine Fehlermeldung erhalten, die beinhaltet 4, irgendwie?

+2

Nicht als eine Antwort zu veröffentlichen, weil ich keine Beweise zur Hand haben, aber ich erinnere mich, dies in der Vergangenheit zu tun, und ich denke, der Standard sagt, dass static_assert ein String Literal nehmen muss, und als Konsequenz können Sie verwende stattdessen keinen constexpr-Ausdruck. Es tut uns leid. – je4d

+0

Beachten Sie, dass Ihr Fix nicht wirklich 'static_assert' verwendet. Es erfindet nur die Grundidee eines Konstrukts neu, das nichts weiter tut, als zu bestehen oder zu versagen. Die Sache, die das "Drucken" macht, muss auch den Test durchführen, so dass Sie das Problem mit SFINAE lösen müssen. – Potatoswatter

Antwort

11

die Grammatik für Erklärungen gegeben Zitiert in §7/​​1 [dcl.dcl]:

static_assert-declaration:

static_assert (constant-expression , string-literal) ;

Die Norm sagt, dass es eine Stringliteral sein muss, so dass man kein Glück; Sie können eine Contexpr-Funktion nicht verwenden, um Ihre Fehlermeldung zu erstellen.

Sie können jedoch jede Präprozessor-Magie, die Sie mögen, verwenden, um ein String-Literal zu generieren, um dorthin zu gelangen. Wenn PI_INT ein #define ist anstelle eines constexpr int, könnten Sie so etwas wie folgt verwenden:

#define PI_INT 4 
#define pi_err_str_(x) #x 
#define pi_err_str(x) pi_err_str_(x) 
#define pi_int_err "PI_INT must be 3, not " pi_err_str(PI_INT) 

static_assert(PI_INT == 3, pi_int_err); 

Ausgang:

error: static assertion failed: "PI_INT must be 3, not 4"


bearbeiten in Reaktion von OP Kommentar und aktualisierte Frage

Is there a way to write a macro that can generalize this so that I can do something like ... and get an error message that involves 4, somehow?

Sicher, ein bisschen Vorverarbeitung oder Magie kann man erkennen, verallgemeinert, Sie sind unter der Annahme, glücklich auf Compiler-spezifische Fehlermeldung Verhalten angewiesen zu sein:

#define strcat_(x, y) x ## y 
#define strcat(x, y) strcat_(x, y) 
#define PRINT_VALUE(x) template <int> struct strcat(strcat(value_of_, x), _is); static_assert(strcat(strcat(value_of_, x), _is)<x>::x, ""); 

constexpr int PI_INT = 4; 
PRINT_VALUE(PI_INT) 

stackoverflow/13465334.cpp:20:1: error: incomplete type ‘value_of_PI_INT_is<4>’ used in nested name specifier

Wie bei anderen Compilern, weiß ich nicht, was Sie ohne Weiteres tun können, aber Sie Vielleicht möchten Sie sich eine Kopie von boost's static_assert.hpp ansehen, um zu sehen, ob einer der dort verwendeten Tricks verwendet werden kann, um einen ausgewerteten Template-Arg zu erhalten.

+0

Das beantwortet die letzten zwei Drittel meiner Frage. Das erste Drittel, über das Drucken von "conexpr" -Werten zum Kompilieren, ist nicht so offensichtlich. Siehe die Bearbeitung, die ich gerade gemacht habe. –

+0

Gibt es eine Möglichkeit, dies im Blockbereich zu tun (zum Drucken innerhalb von Vorlagenfunktionen)? – mxmlnkn