2013-02-11 5 views
6

Wie verlasse ich mich zuverlässig auf alles, was kein String-Literal ist? Beispiel: Im folgenden Code habe ich versucht, das Standard-Asser-Makro zu umbrechen, aber alles für die Nachricht, die kein String-Literal ist, statisch abzulehnen (da bei der Assertion alles außer einem String-Literal zur Laufzeit nicht angezeigt wird) löst aus).Wie erkennt man ein String-Literal mit type_traits?

#include <cassert> 
#include <string> 
#include <type_traits> 

#define my_assert(test, message)\ 
    static_assert(\ 
     (\ 
      !std::is_pointer<decltype(message)>::value &&\ 
      !std::is_array<decltype(message)>::value\ 
     ),\ 
     "literal string required"\ 
    );\ 
    assert((message, (test))); 

int main() { 
    my_assert(1 == 1, "one equals one"); 
    my_assert(1 == 2, "one equals two"); 

    { 
     const char *msg = "one equals one"; 
     //my_assert(1 == 1, msg); // triggers static_assert 
    } 

    { 
     const char msg[] = "one equals one"; 
     //my_assert(1 == 1, msg); // triggers static_assert 
    } 

    { 
     const std::string msg = "one equals one"; 
     //my_assert(1 == 1, msg.c_str()); // triggers static_assert 
    } 

    { 
     const int msg = 3; 
     my_assert(1 == 1, msg); // should trigger static_assert 
    } 
} 

Wie Sie sehen können, ist die Prüfung über die von dem type_traits Header versehen Tests durchgeführt, und, meist, dieser Code funktioniert wie vorgesehen (mit gcc 4.7.2 getestet). Es sucht jedoch nicht so sehr nach Zeichenfolgenliteralen, sondern lehnt auch gewöhnliche Dinge ab, die ein Programmierer verwenden könnte.

Die Lösung, die ich habe, mag für das obige Beispiel gut genug sein, aber ich würde diese oder eine ähnliche Technik auch in anderen Situationen verwenden.

Also die Frage ist, wie verwende ich zuverlässig type_traits (oder einen anderen Standard-Mechanismus) zu static_sert auf alles außer einem String-Literal?

+0

tun, wenn eine Assertion fehlschlägt? Wenn ja, dann posten Sie bitte eine andere Frage. Das Standard '' assert() 'Makro ist meiner Meinung nach ziemlich nutzlos, aber es gibt sehr gute Möglichkeiten, eigene zu schreiben und eine Nachricht zusammen mit den Werten der beteiligten Variablen anzuzeigen. – Ali

+0

@Ali danke, aber meine Frage hat sehr wenig mit 'assert()' zu tun, außer dass es ein motivierendes Vehikel war, einen Grund zu demonstrieren, warum die Antwort auf die Frage nützlich sein könnte. Ich bekomme auch eine gute Nachricht, wenn die Assert nicht mit dem Standard von gcc/libc geliefert wird. Es gibt natürlich ausgefeiltere Möglichkeiten Assertionen zu machen, aber das ist nicht wirklich der Punkt meiner Frage - wie gesagt, ich interessiere mich dafür, wie man ein String-Literal gegen andere Dinge erkennt. (Meine eigene Antwort unten scheint den Trick ziemlich genau zu machen.) – wjl

+0

OK, ich dachte, du hättest eine schicke Behauptung brauchen. Ok, viel Glück! – Ali

Antwort

5

Hier ist das Beste, was ich bekommen konnte, die alles, was ich an ihm werfen abzulehnen scheint, akzeptiert aber noch Literalzeichenfolgen:

#define my_assert(test, message)\ 
    static_assert(\ 
     (\ 
      std::is_convertible  <decltype(message), const char *>::value &&\ 
      !std::is_rvalue_reference <decltype(message)>::value &&\ 
      !std::is_pointer   <decltype(message)>::value &&\ 
      !std::is_array   <decltype(message)>::value &&\ 
      !std::is_class   <decltype(message)>::value\ 
     ),\ 
     "string literal required"\ 
    );\ 
    assert((message, (test))) 

wäre ich sehr daran interessiert zu wissen, ob dies tatsächlich erschöpfend ist richtig und/oder wenn es einen einfacheren Weg gibt, diese Erkennung durchzuführen.

0

'decltype ("einige Zeichenfolge")' eines String-Literals gibt "const char (&) [n]" Typ zurück. So scheint es, gibt prägnanter ist, im Vergleich zu the following answer, wie es zu erkennen: Sie eine Nachricht tatsächlich angezeigt werden sollen

template<typename T> 
struct IsStringLiteral : 
    std::is_same< 
     T, 
     std::add_lvalue_reference_t<const char[std::extent_v<std::remove_reference_t<T>>]> 
    > 
{}; 

(online demo)