2013-02-11 13 views
6

In che modo affidabile static_assert su tutto ciò che non è una stringa letterale?Come rilevare una stringa letterale con type_traits?

Ad esempio, nel seguente codice, ho tentato di racchiudere la macro di asserzione standard, ma di rifiutare staticamente qualsiasi cosa per il messaggio che non è una stringa letterale (poiché qualsiasi cosa tranne una stringa letterale non verrà visualizzata in fase di esecuzione quando si asserisce trigger).

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

Come si può vedere, il test è fatto attraverso le prove previste dalla intestazione type_traits, e, per lo più , questo codice funziona come previsto (testato con gcc 4.7.2). Tuttavia, non cerca specificamente i letterali stringa quanto rifiuta semplicemente le cose comuni che un programmatore potrebbe usare sul posto.

La soluzione che ho può essere abbastanza buona per l'esempio sopra, ma mi piacerebbe usare questo, o una tecnica simile anche in altre situazioni.

Quindi la domanda è: come faccio a utilizzare in modo affidabile type_traits (o un altro meccanismo standard) per static_assert su nulla tranne una stringa letterale?

+0

si fa realmente desidera visualizzare un messaggio quando un'asserzione fallisce? Se è così allora si prega di inviare un'altra domanda. La macro standard 'assert()' è piuttosto inutile secondo me, ma ci sono modi veramente buoni di scrivere i propri, visualizzando un messaggio insieme ai valori delle variabili coinvolte. – Ali

+0

@Ali ringrazia, ma la mia domanda ha molto poco a che fare con 'assert()' a parte che è stato un veicolo motivante per dimostrare una ragione per cui la risposta alla domanda potrebbe essere utile. Alreay ricevo un grande messaggio quando l'assert non funziona usando quello standard fornito da gcc/libc. Esistono ovviamente modi più sofisticati per fare asserzioni, ma non è proprio questo il punto della mia domanda - come ho detto, sono interessato a come rilevare una stringa letterale rispetto ad altre cose. (La mia risposta qui sotto sembra fare il trucco abbastanza da vicino.) – wjl

+0

OK, pensavo che avessi bisogno di una dichiarazione di fantasia. Beh buona fortuna! – Ali

risposta

5

qui è la migliore ho potuto ottenere, che sembra respingere qualcosa che buttare a questo, ma accetta comunque le stringhe letterali:

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

Sarei molto interessato a sapere se questo in realtà è esaurientemente corretto e/o se esiste un modo più semplice per eseguire questa rilevazione.

0

'decltype ("una stringa")' di una stringa letterale restituisce "const char (&) [n]" type. Così, sembra che ci sia più succinta, in confronto con the following answer, modo di rilevare che:

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)

Problemi correlati