Stringhe in stile C come argomenti del modello?

Le stringhe C-Style possono essere utilizzate come argomenti del modello?

Provai:

template  struct X { const char *GetString() const { return str; } }; int main() { X x; cout<<x.GetString(); } 

E anche se non ho lamentele sulla definizione della class, l’istanziazione restituisce 'X' : invalid expression as a template argument for 'str' (VC).

Una stringa letterale non può essere utilizzata come argomento modello .

Aggiornamento: al giorno d’oggi, alcuni anni questa domanda è stata posta e ha risposto, è ansible utilizzare i valori letterali stringa come argomenti del modello. Con C ++ 11, possiamo usare i pacchetti di caratteri come argomenti del template ( template ) ed è ansible passare una stringa letterale a tale modello.

Ciò funzionerebbe, tuttavia:

 template  struct X { const char *GetString() const { return str; } }; char global_string[] = "String"; int main() { X x; cout< 

Ho saputo, questo argomento è un po ‘vecchio ma ho messo questo commento se qualcuno è interessato. Ho raggiunto modelli con stringa letterale passante come argomento con combinazione di MACRO.

Ho fatto un esempio di codice,

#include  #include  #include  #include  #include  using namespace std; #define MAX_CONST_CHAR 100 #define MIN(a,b) (a)<(b)?(a):(b) #define _T(s)\ getChr(s,0),\ getChr(s,1),\ getChr(s,2),\ getChr(s,3),\ getChr(s,4),\ getChr(s,5),\ getChr(s,6),\ getChr(s,7),\ getChr(s,8),\ getChr(s,9),\ getChr(s,10),\ getChr(s,11),\ getChr(s,12),\ getChr(s,13),\ getChr(s,14),\ getChr(s,15),\ getChr(s,16),\ getChr(s,17),\ getChr(s,18),\ getChr(s,19),\ getChr(s,20),\ getChr(s,21),\ getChr(s,22),\ getChr(s,23),\ getChr(s,24),\ getChr(s,25),\ getChr(s,26),\ getChr(s,27),\ getChr(s,28),\ getChr(s,29),\ getChr(s,30),\ getChr(s,31),\ getChr(s,32),\ getChr(s,33),\ getChr(s,34),\ getChr(s,35),\ getChr(s,36),\ getChr(s,37),\ getChr(s,38),\ getChr(s,39),\ getChr(s,40),\ getChr(s,41),\ getChr(s,42),\ getChr(s,43),\ getChr(s,44),\ getChr(s,45),\ getChr(s,46),\ getChr(s,47),\ getChr(s,48),\ getChr(s,49),\ getChr(s,50),\ getChr(s,51),\ getChr(s,52),\ getChr(s,53),\ getChr(s,54),\ getChr(s,55),\ getChr(s,56),\ getChr(s,57),\ getChr(s,58),\ getChr(s,59),\ getChr(s,60),\ getChr(s,61),\ getChr(s,62),\ getChr(s,63),\ getChr(s,64),\ getChr(s,65),\ getChr(s,66),\ getChr(s,67),\ getChr(s,68),\ getChr(s,69),\ getChr(s,70),\ getChr(s,71),\ getChr(s,72),\ getChr(s,72),\ getChr(s,72),\ getChr(s,73),\ getChr(s,74),\ getChr(s,75),\ getChr(s,76),\ getChr(s,77),\ getChr(s,78),\ getChr(s,79),\ getChr(s,80),\ getChr(s,81),\ getChr(s,82),\ getChr(s,83),\ getChr(s,84),\ getChr(s,85),\ getChr(s,86),\ getChr(s,87),\ getChr(s,88),\ getChr(s,89),\ getChr(s,90),\ getChr(s,91),\ getChr(s,92),\ getChr(s,93),\ getChr(s,94),\ getChr(s,95),\ getChr(s,96),\ getChr(s,97),\ getChr(s,98),\ getChr(s,99),\ getChr(s,100) #define getChr(name, ii) ((MIN(ii,MAX_CONST_CHAR)) class E { public: string *str; E(){ std::vector vec = {Chars_...}; str = new string(vec.begin(),vec.end()); } ~E() { delete str; } }; int main(int argc, char *argv[]) { E<_T("Any template can pass const strings literals")> e; printf("%s",e.str->c_str()); } 

Funziona con g + + 4.6 e passando argomento -std = c ++ 0x, e ha un limite di 100 caratteri ma, naturalmente, può essere più grande di quanto si desideri. Forse questa tecnica non è ben ottimizzata, ma sarà più produttiva che dichiarare le variabili esterne necessarie (ne sono sicuro;))

Vincoli: la stringa letterale deve essere uno e l’ultimo argomento del modello a causa del passaggio di argomenti variadics.

EDIT : Grazie a Padek ha testato che questo pezzo di codice funziona anche con Visual Studio 2017 ma cambiando strlen per sizeof (nome) / sizeof (* nome) .

Mi spiace postare su una domanda così vecchia, ma ecco quello che ritengo sia l’approccio più pulito per passare in realtà un argomento letterale come argomento senza utilizzare la memoria.

Codifica la stringa come tipo:

 template  using tstring = std::integer_sequence; 

Crea un operatore letterale definito dall’utente:

 template  constexpr tstring operator""_tstr() { return { }; } 

E usa la specializzazione parziale per recuperare i dati del personaggio secondo necessità:

 template  struct X; template  struct X> { const char* GetString() const { static constexpr char str[sizeof...(elements) + 1] = { elements..., '\0' }; return str; } }; 

Questo ti permette di scrivere:

 X 

Il letterale definito dall’utente utilizza la funzionalità non standard ( n3599 ) non in C ++ 14, ma è supportata dalle recenti build GCC e Clang e, si spera, sarà riconsiderata per C ++ 1z.

No, non puoi lavorare con stringhe letterali al momento della compilazione. I migliori che si possono ottenere sono i letterali bizzarri e bizzarri (es. 'abcd' ) usati da alcuni parser in fase di compilazione. Sono menzionati nel §2.13.2.1 :

Un letterale di carattere ordinario che contiene più di un c-char è un letterale multi-carattere. Un valore letterale multiplo ha tipo int e valore definito dall’implementazione.

In C ++ 0x ci potrebbero essere dei modi per aggirare questo limite, anche se con i nuovi valori letterali delle stringhe , Arctic Interactive ha un interessante articolo su questo.

Con C ++ 11 è ansible rappresentare in modo abbastanza accurato stringhe letterali come argomenti di template variadici, ovvero una raccolta di parametri di template int. Ho messo insieme un esempio di proof of concept che imposta uno di questi template senza dover scrivere manualmente foo<16, 73, 51 ...> per ogni stringa del genere.

Esempio:

 // The template we want to pass a string to template  struct foo { // It needs one helper function for decltype magic, this could be avoided though template  static foo add_one(); }; // This is the string we want to use with foo, simulating foo<"Hello world!" __FILE__>: constexpr const char *teststr = "Hello world!" __FILE__; // Get char N of a string literal constexpr int strchr(const char *str, int N) { return str[N]; } // recursive helper to build the typedef from teststr template  struct builder { typedef typename builder::type child; typedef decltype(child::template add_one()) type; }; template  struct builder { typedef foo type; }; // compile time strlen constexpr int slen(const char *str) { return *str ? 1 + slen(str+1) : 0; } int main() { builder::type test; // compile error to force the type to be printed: int foo = test; } 

Avrai bisogno almeno di gcc 4.6 per constexpr e potrebbe usare ancora un po ‘di smalto ma l’errore del compilatore che ottengo indica che il tipo è stato costruito in modo sano:

 error: cannot convert 'builder<19>::type {aka foo<72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 115, 108, 105, 116, 46, 99, 99, 0>}' to 'int' in initializatio 

No. Secondo lo standard C ++ 14.3.2 / 1:

Un argomento modello per un parametro di modello non di tipo, non modello deve essere uno di:
– una costante-espressione integrale di tipo integrale o di enumerazione; o
– il nome di un parametro template non di tipo; o
– l’indirizzo di un object o funzione con collegamento esterno, compresi i modelli di funzione e gli id ​​di modello di funzione ma esclusi i membri di class non statici, espressi come & id-expression dove & è opzionale se il nome si riferisce a una funzione o array, o se il parametro template corrispondente è un riferimento o
– un puntatore al membro express come descritto in 5.3.1.

Le stringhe non sono nella lista.

È ansible utilizzare l’indirizzo di stringa con collegamento esterno come parametro di modello, ad esempio:

 template  class My { public: void do_stuff() { std::cout << "zzz"; } }; const char* str; int main() { My<&str> zz; zz.do_stuff(); printf("Result: %d %d \n", 60 % 10 + 1, (60 % 10 ) + 1 ); } 

Il C ++ non conosce le stringhe. Conosce solo “matrici di caratteri” e il letterale sarebbe il puntatore all’array. Quindi, se si usasse il “valore” della stringa come parametro del template, si utilizzerà effettivamente il valore del puntatore.