2015-03-04 7 views
8

Ho scritto diverse funzioni di constexpr e li uso in static_asserts per controllare alcuni limiti di risorse. Ma mi piacerebbe non solo imporre il predicato in fase di compilazione, ma anche vedere i valori effettivi calcolati durante il normale processo di compilazione o almeno quando l'asserzione fallisce.Come stampare il risultato di un calcolo in fase di compilazione in C++?

Esistono modi per stampare i messaggi di stringa durante la compilazione, ma che cosa significa stampare i risultati dei calcoli di constexpr?

+3

L'argomento del messaggio 'static_assert' non può farlo. –

+2

si potrebbe fare uso della diagnostica del compilatore regolare forzando un tipo incompleto in caso di errore, che dovrebbe portare alla visualizzazione degli argomenti del template nell'output del compilatore, [come qui] (http://coliru.stacked-crooked.com/a/ d2a8871788e97987) –

+0

Posso farlo con VC++ (vedi la mia risposta). Forse qualcuno potrebbe provare a vedere se la stessa tecnica può essere utilizzata in gcc – JavaMan

risposta

5

Ecco un codice che sfrutta i messaggi diagnostici di gcc per stampare i valori di interesse dopo un messaggio di asserzione. Per trovare i valori di interesse, non vi resta che cercare la stringa di errore per T x =:

#include <string> 

template <class T, T x, class F> 
void transparent(F f) { f(); } 


template <bool B> 
constexpr void my_assert() { 
    static_assert(B, "oh no"); 
} 

template <int X> 
void f() { 
    transparent<int, X+7>([]{ 
     transparent<long, X*X*X>([]{ 
      my_assert<X+10==-89>(); });}); 
} 

int main() { 
// f<3>(); 
    f<4>(); 
// f<-99>(); 
} 

Ecco l'errore che mi ha fatto:

g++ h.cpp -std=c++11 h.cpp: In instantiation of ‘constexpr void my_assert() [with bool B = false]’: h.cpp:16:34: required from ‘f() [with int X = 4]::__lambda0::__lambda1’ h.cpp:15:35: required from ‘struct f() [with int X = 4]::__lambda0::__lambda1’ h.cpp:16:38: required from ‘f() [with int X = 4]::__lambda0’ h.cpp:14:28: required from ‘struct f() [with int X = 4]::__lambda0’ h.cpp:16:41: required from ‘void f() [with int X = 4]’ h.cpp:21:10: required from here h.cpp:9:5: error: static assertion failed: oh no static_assert(B, "oh no"); ^ h.cpp:4:6: error: ‘void transparent(F) [with T = long int; T x = 64l; F = f() [with int X = 4]::__lambda0::__lambda1]’, declared using local type ‘f() [with int X = 4]::__lambda0::__lambda1’, is used but never defined [-fpermissive] void transparent(F f) { f(); } ^ h.cpp:4:6: error: ‘void transparent(F) [with T = int; T x = 11; F = f() [with int X = 4]::__lambda0]’, declared using local type ‘f() [with int X = 4]::__lambda0’, is used but never defined [-fpermissive]

Si noti che in grassetto le parti

+0

Funzionante, grazie! Qualche idea su come emettere un messaggio di avviso in modo che la compilazione continui? –

0

Il mio codice VC++ che stampa, durante la compilazione, il valore di tutte le costanti di tempo di compilazione desiderate (ad es. Sizeof structures) e continua la compilazione senza errori:

// cpptest.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
//#define VALUE_TO_STRING2(x) #x 
//#define VALUE_TO_STRING(x) VALUE_TO_STRING2(x) 


#define TO_STRING(x) #x 
#define FUNC_TEMPLATE_MSG(x,y) "[" x "]""["TO_STRING(y)"]" 

template<unsigned int N,unsigned int M> 
int printN() 
{ 
#pragma message(FUNC_TEMPLATE_MSG(__FUNCSIG__ ,1)) 

    return 0; 
}; 



struct X { 
    char a[20]; 
    int b; 
}; 
struct Y { 
    char a[210]; 
    int b; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
printN<sizeof(X),__COUNTER__>(); 
printN<sizeof(Y),__COUNTER__>(); 
//..as many compile time constants as you like 
} 

Esempio di output prodotto da VC++ 2010. Il valore di destinazione è il primo valore del parametro del modello di funzione (0x18 e 0xd8 nell'esempio) che VC++ ha scelto stranamente di produrre come valore esadecimale !!

1>------ Build started: Project: cpptest, Configuration: Release Win32 ------ 
1> cpptest.cpp 
1> [int __cdecl printN<0x18,0x0>(void)][1] 
1> [int __cdecl printN<0xd8,0x1>(void)][1] 
1> Generating code 
1> Finished generating code 
1> cpptest.vcxproj -> c:\work\cpptest\Release\cpptest.exe 
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== 

La tecnica principale utilizzata qui è che un corso di ogni funzione di modello di istanza, la direttiva #pragma message() viene invocato una volta. La macro specifica di Microsoft __FUNCSIG__ può visualizzare la firma della funzione di contenitore e quindi il valore intero utilizzato in ogni istanza specifica del modello di funzione. Dare COUNTER come secondo parametro template è assicurarsi che 2 interi dello stesso valore siano ancora considerati diversi. Il 1 nella direttiva #pragma non è utile in questo caso ma può essere utilizzato come identificativo nel caso in cui si abbia più di 1 direttiva e la finestra di output sia piena di messaggi disordinati.

Problemi correlati