2015-07-09 16 views
19

In C++ 11 es legal ist zum Beispiel zu schreiben,:Gibt es eine Möglichkeit, eine static_assert in einen Ausdruck in ISO C++ 11 zu gleiten?

int b = (some_function_returning_void(), 1020); 

Und Sie werden wieder 1020. bekommen, aber es wird nicht zulassen, schreiben:

int b = (static_assert(2 > 1, "all is lost"), 304); 

Die documentation erklärt die Stellen, an denen Recht static_assert (a keyword, scheinbar) können auftreten: bei Block Umfang

eine statische assert Deklaration (als Block Anmeldung) und innerhalb einer Klasse Körper auftreten kann (wie Mitglied Erklärung)

nur für das Heck von ihm habe ich versucht, ein paar Dinge, bis das funktionierte:

int b = ({static_assert(2 > 1, "all is lost"); 304;}); 

Aber mit -Wpedantic ich "warning: ISO C++ forbids braced-groups within expressions" bekommen. Interessanterweise werden diese als "Anweisungsausdrücke" und used in the Linux kernel bezeichnet.

Aber lassen Sie uns vorstellen, ich möchte -Wpedantic bleiben. Gibt es saubere Workarounds?

+2

Kontext: Ich versuche, ein Makro zu schreiben, das in ANSI C89 funktioniert, fügt jedoch eine zusätzliche Überprüfung hinzu, wenn es als ISO C++ 11 erstellt wird. Ja ich bin komisch, danke für die Nachfrage. Oh, das war keine Frage? Kommentar, wenn Sie dies in 9999999999999999999 lesen .... – HostileFork

+1

Sie könnten das statische Assert in einen Lambda-Ausdruck setzen. '[] {Static_assert (..); }(), 1020' – dyp

+0

@dyp Interessante Idee ... obwohl in meinem unten stehenden Hinweis frage ich, was die Auswirkungen davon für ein Makro sein könnte, viele, viele Male aufgerufen ... – HostileFork

Antwort

23

Wie @dyp in den Kommentaren erwähnt, können Sie die Komma-Operator missbrauchen und einen Lambda-Ausdruck:

([]{static_assert(true,"");}, 42) 

Live on Coliru

+0

Das funktioniert definitiv! Obwohl eine Frage, die ich haben könnte, ist, ob dieses Makro sehr stark benutzt wird ... wie Zehntausende von Malen, gibt es einen Punkt, an dem das Verfolgen all dieser Lambdas den Compiler belastet? Wenn Sie einen nicht optimierten Build erstellen, werden Sie viele Entitäten zum Nachverfolgen haben, die in einem Debugging-Szenario auftauchen könnten? – HostileFork

+0

@HostileFork Der Lambda-Ausdruck erzeugt formal einen neuen Typ (jedes Mal, wenn er im Code auftritt) und ein Objekt von diesem neuen Typ (jedes Mal, wenn es aufgerufen wird). Wenn das ein Problem wird, könnten Sie vielleicht stattdessen eine Klassenvorlage verwenden? 'template struct sassert {statischer_assert (cond,"! "); static bool const Wert = false; }; (sassert <(2> 1)> :: value && "alles ist verloren", 1020) ' – dyp

+0

@dyp Yeah, ich dachte über diese Zeilen nach ... seit der Schaffung aller Arten war meine Sorge) als in nicht wahrscheinlich eine Achse Der Compiler ist für den Vergleich mit den Templates optimiert. Aber fragte sich, ob es etwas saubereres aussah, und das Lambda ist in der Tat sauberer aussehend ... – HostileFork

9

static_assert ist nicht ein Ausdruck (im Gegensatz zu sizeof), so dass Sie nicht verwenden können, wo ein Ausdruck erforderlich wäre.

Es ist nicht einmal ein Ausdruck mit Typ void (Interessanterweise ist throw ein Ausdruck des Typs void), so können Sie es nicht einmal in einem ternären verwenden.

Anweisung Ausdrücke sind nicht Standard C++, so würde ich davon abraten, sie zu verwenden.

Ein Lambda

int b = []{ 
    static_assert(2 > 1, "all is lost"); return 304; 
}(); 

oder

int b = ([]{static_assert(2 > 1, "all is lost");}, 304); 

kaum sauber ist. (Das zweite Lambda sieht aus wie eine Haaresbreite davon entfernt, undefiniert zu sein).

+0

Netter Vorschlag mit den Lambdas, Leute. Wie für die zweite, warum sollte es weniger definiert sein als nur '[] {}'? Ich würde denken, dass es nicht einfacher ist, es zu optimieren ... – HostileFork

+0

Ich mache mir Sorgen, dass die erste Sache nicht auswertbar ist. Der Komma-Operator wertet alle Ausdrücke von links nach rechts aus. – Bathsheba

+0

Es ist jedoch auf den Wert des Lambda auswertbar, nicht wahr? 'auto x = [] {};'? – HostileFork

3

Was ist mit einer Funktionsvorlage:

template<int T> void my_static_assert() 
{ 
    static_assert(T, "asserted"); 
} 

Dann Sie können den Komma-Operator verwenden, Sie müssen nicht einmal die Funktion aufrufen:

int x = (my_static_assert<(2 > 1)>, 2001); 

Vielleicht brauchen Sie hier und da ein paar Klammern, um den Parser glücklich zu machen. Und Sie verlieren die statische Assert-Nachricht, aber es funktioniert.