2012-12-05 15 views
8

Voglio scrivere una funzione C++ 11 che accetterà solo stringhe letterali come parametro:C++ 11 Funzione che accetta solo valori letterali stringa?

void f(const char* s) { static_assert(s is a string literal); ... } 

Cioè:

f("foo"); // OK 

char c = ...; 
f(&c); // ERROR: Doesn't compile 

string s = ...; 
f(s.c_str()); // ERROR: Doesn't compile 

etc 

Esiste un modo per implementare questo? La firma della funzione è aperta alle modifiche, così come l'aggiunta di macro o altre funzionalità linguistiche.

Se ciò non è possibile, qual è l'approssimazione più vicina? (I letterali definiti dall'utente possono essere utili in ogni caso?)

Se non c'è un modo specifico per la piattaforma in GCC 4.7/Linux?

+0

Cosa farai con stringhe letterali che non puoi fare con non-stringhe-letterali? E che ne dici di passare una variabile 'const char * const' inizializzata usando una stringa letterale? O un riferimento a 'const char (& array) []' a una stringa letterale? – hvd

+2

Questo non è possibile, poiché i valori letterali stringa sono solo array 'char const [N]' e quindi non sono distinguibili da essi. – Xeo

+0

Forse usando un letterale stringa definito dall'utente che converte in un tipo che ha i dati di sola lettura quando è un riferimento di questo valore (quindi non può essere una variabile denominata). L'obiettivo è quello di far rispettare che la stringa viene letteralmente digitata nel codice al punto di chiamata e compilata staticamente nell'immagine dell'applicazione. –

risposta

12

penso che il più vicino si sta per ottenere è questo

template<int N> 
void f(const char (&str)[N]){ 
    ... 
} 

Sarà compilare con letterali e array, ma non puntatori.

+0

Potrebbe essere possibile impedire ulteriormente che funzioni con la maggior parte degli array non-letterali con un uso intelligente di 'std :: enable_if <>'. Vedi http://stackoverflow.com/questions/14805011/how-to-detect-a-string-literal-with-type-traits per un esempio di cosa mettere in enable_if (anche se quella domanda usa static_assert, è lo stesso concetto). – wjl

3

Un'alternativa potrebbe essere quella di fare in modo che un'estensione GCC verifichi in fase di compilazione che la particolare funzione venga chiamata solo con una stringa letterale.

È possibile utilizzare MELT per estendere GCC. MELT è un linguaggio di dominio di alto livello per estendere il compilatore GCC ed è molto adatto per il tipo di controllo che si desidera.

Fondamentalmente, si dovrebbe aggiungere un nuovo passaggio all'interno di GCC e il codice che passa in MELT che avrebbe trovato ogni inganno che è una chiamata alla propria funzione e verificare che l'argomento sia effettivamente una stringa letterale. L'esempio ex06 su melt-examples dovrebbe ispirarti. Quindi iscriviti allo [email protected] e fai le tue domande specifiche su MELT lì.

Naturalmente, questo non è un approccio infallibile: la funzione potrebbe essere chiamata indirettamente tramite puntatori e potrebbe ad es. avere una stringa letterale parziale, ad es. f("hello world I am here"+(i%4)) è concettualmente una chiamata con una stringa letterale (ad esempio nel segmento .rodata), ma non nel codice generato né nel gimple.

1

Io uso questo:

// these are used to force constant, literal strings in sqfish binding names 
// which allows to store/copy just the pointer without having to manage 
// allocations and memory copies 
struct _literalstring 
{ 
    // these functions are just for easy usage... not needed 
    // the struct can be empty 
    bool equal(_literalstring const *other) { return !strcmp((const char *)this, (const char *)other); } 
    bool equal(const char *other) { return !strcmp((const char *)this, other); } 
    const char *str(void) { return (const char *)this; } 
    bool empty(void) { return *(const char *)this == 0; } 
}; 

typedef _literalstring *LITSTR; 

constexpr LITSTR operator "" _LIT(const char *s, size_t) { 
    return (LITSTR)s; 
} 

Poi basta dichiarare la funzione in questo modo:

void myFunc(LITSTR str) 
{ 
    printf("%s\n", str->str()); 
    printf("%s\n", (const char *)str); 
    const char *aVar = str->str(); 
    const char *another = (const char *)str; 
} 

e si chiama in questo modo:

myFunc("some text"_LIT); 

Se fate qualcosa così:

myFunc("some text"); 
myFunc(aTextVariable); 

si ottiene un errore del compilatore.

Problemi correlati