2012-11-20 17 views
12

Czy istnieje sposób wydrukowania wartości wartości constexpr lub #define d podczas kompilacji? Chcę równowartość std::cout << lub jakiś sposób na zrobienie czegoś podobnegoekwiwalent std :: cout w czasie kompilacji lub static_assert stringification wartości stałych w czasie kompilacji w 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))); 

Edit: mogę zrobić podstawowe kompilacji drukowania constexpr s, przynajmniej na gcc wykonując coś jak

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"); 

co daje mi 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, z drugiej strony, jest mniej przydatne, i po prostu mówi error: incomplete type is not allowed) Czy istnieje sposób, aby napisać makro, które można uogólnić to tak, że można zrobić coś jak

constexpr int PI_INT = 4; 
PRINT_VALUE(PI_INT) 

i pojawia się komunikat o błędzie, który obejmuje 4, jakoś?

+2

Nie zamieszczam tego jako odpowiedzi, ponieważ nie mam dowodów do przekazania, ale pamiętam, że próbowałem to zrobić w przeszłości i myślę, że standard mówi, że static_assert musi przyjmować literał ciągu, aw konsekwencji możesz zamiast tego użyj wyrażenia constexpr. Przepraszam. – je4d

+0

Zauważ, że twoja poprawka nie używa w ogóle 'static_assert'. Po prostu odkrywa na nowo podstawową ideę konstruktu, który nic nie robi, ale kończy się niepowodzeniem. Rzecz, która wykonuje "drukowanie" również musi wykonać test, więc utknąłeś rozwiązując cały problem z SFINAE. – Potatoswatter

Odpowiedz

11

Cytowanie gramatyki podane dla deklaracji w §7/​​1 [dcl.dcl]:

static_assert-declaration:

static_assert (constant-expression , string-literal) ;

Norma mówi, że musi być ciąg dosłowne, więc masz pecha; nie można użyć funkcji constexpr do skonstruowania komunikatu o błędzie.

Można jednak użyć dowolnej magii preprocesora, którą lubisz, aby wygenerować ciąg literału, aby tam wejść. Jeśli PI_INT jest #define zamiast constexpr int, można użyć mniej więcej tak:

#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); 

wyjściowa:

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


Edit w odpowiedzi na komentarz przez OP i zaktualizowane pytanie

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?

Oczywiście, trochę preprocesu lub magia można generalizować, że zakładając, że jesteś szczęśliwy, że zależne od kompilatora specyficzne zachowanie komunikat o błędzie:

#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

jak dla innych kompilatorów, nie wiem co można zrobić od ręki, ale może chcieć spojrzeć na kopię boost's static_assert.hpp, aby sprawdzić, czy któraś z wykorzystanych trików może być wykorzystana do wydrukowania wydrukowanego szablonu oceny.

+0

To odpowiada na ostatnie dwie trzecie mojego pytania. Pierwsza trzecia, dotycząca drukowania wartości 'constexpr' podczas kompilacji, nie jest tak oczywista. Zobacz edytowaną właśnie edycję. –

+0

Jakikolwiek sposób, aby to działało w zakresie bloku (do drukowania wewnątrz funkcji szablonowych)? – mxmlnkn