2015-03-04 5 views
8

Ich habe mehrere constexpr-Funktionen geschrieben und verwende sie in static_asserts, um einige Ressourcenlimits zu steuern. Aber ich möchte nicht nur das Kompilierzeitprädikat erzwingen, sondern auch die tatsächlichen Werte sehen, die während des normalen Kompilierungsprozesses oder zumindest bei fehlgeschlagener Assertion berechnet werden.Wie kann das Ergebnis einer Kompilierzeitberechnung in C++ gedruckt werden?

Es gibt Möglichkeiten, String-Nachrichten während der Kompilierung zu drucken, aber was ist mit dem Drucken der Ergebnisse von conexpr-Berechnungen?

+3

Shame 'static_assert's Nachrichtenargument kann dies nicht tun. –

+2

können Sie die normale Compilerdiagnose verwenden, indem Sie einen unvollständigen Typ bei fehlgeschlagenem Zustand erzwingen, was dazu führen sollte, dass Template-Argumente in der Compilerausgabe sichtbar sind [wie hier] (http://coliru.stacked-crooked.com/a/ d2a8871788e97987) –

+0

Ich kann dies mit VC++ tun (siehe meine Antwort). Vielleicht könnte jemand versuchen zu sehen, ob die gleiche Technik in GCC verwendet werden kann – JavaMan

Antwort

5

Hier ist ein Code, der die Diagnosemeldungen von gcc ausnutzt, um nach einer Assert-Nachricht Werte von Interesse zu drucken. Um die Werte von Interesse zu finden, müssen Sie nur die Fehlerzeichenfolge für T x = suchen:

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

Hier ist der Fehler ist, dass es hat mir:

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]

Beachten Sie, dass Teile bolded

+0

Das funktioniert, danke! Gibt es eine Idee, wie eine Warnmeldung ausgegeben wird, damit die Kompilierung fortgesetzt wird? –

0

Mein VC++ - Code, der während der Kompilierung den Wert von beliebig vielen Kompilierzeitkonstanten (z. B. sizeof structures) druckt und das Kompilieren ohne Fehler fortsetzt:

// 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 
} 

Beispielausgabe von VC++ 2010 produziert. Der Zielwert ist der erste Funktionsschablonen-Parameterwert (im Beispiel 0x18 und 0xd8), den VC++ als hexadezimalen Wert ausgewählt hat !!

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 ========== 

Die Haupttechnik hier verwendet wird, ist, dass ein während jeder Funktion Vorlage Instanziierung, die #pragma message() Richtlinien einmal aufgerufen werden. Das Microsoft-spezifische Makro __FUNCSIG__ kann die Signatur der enthaltenden Funktion und damit den Integer-Wert anzeigen, der bei jeder spezifischen Instanziierung der Funktionsvorlage verwendet wird. Geben Sie als zweiten Vorlagenparameter COUNTER ein, um sicherzustellen, dass 2 Ganzzahlen mit demselben Wert immer noch als unterschiedlich betrachtet werden. Die 1 in der #pragma Direktive ist hier nicht von Nutzen, kann aber als Identifikator verwendet werden, falls wir mehr als 1 solcher Direktive haben und das Ausgabefenster voller unordentlicher Nachrichten ist.