Parametri di modello non di tipo


93

Capisco che il parametro del modello non di tipo dovrebbe essere un'espressione integrale costante. Qualcuno può far luce perché è così?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

Capisco cos'è un'espressione integrale costante. Quali sono le ragioni per non consentire tipi non costanti std::stringcome nello snippet sopra?


17
Un parametro del modello viene risolto in fase di compilazione.
Etienne de Martel

Risposte:


121

Il motivo per cui non puoi farlo è perché le espressioni non costanti non possono essere analizzate e sostituite durante la compilazione. Potrebbero cambiare durante il runtime, il che richiederebbe la generazione di un nuovo modello durante il runtime, il che non è possibile perché i modelli sono un concetto in fase di compilazione.

Ecco cosa consente lo standard per i parametri del modello non di tipo (14.1 [temp.param] p4):

Un parametro-modello non di tipo deve avere uno dei seguenti tipi (facoltativamente qualificati per cv):

  • tipo integrale o di enumerazione,
  • puntatore a oggetto o puntatore a funzione,
  • lvalore riferimento all'oggetto o lvalore riferimento alla funzione,
  • puntatore al membro,
  • std::nullptr_t.

6
@ALOToverflow: che rientra in "pointer to member". Può essere "puntatore alla funzione membro" o "puntatore ai dati del membro".
Xeo

4
Vale la pena notare che per il caso di puntatori a oggetti (o campi istanza), gli oggetti devono avere durata di memorizzazione statica e collegamento (esterno pre C ++ 11, interno o esterno in C ++ 11), in modo che i puntatori a essi possano essere creato in fase di compilazione.
Theodore Murdock

2
In C ++ 20 questo è ora consentito a condizione che il tipo abbia una forte uguaglianza strutturata, sia un suboggetti letterale, non mutabile / volatile e dove l'operatore di astronave sia pubblico.
Rakete 1111

73

Non è permesso.

Tuttavia, questo è consentito:

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

Vedere §14.1 / 6,7,8 in C ++ Standard (2003).


Illustrazione:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

Produzione:

can assign values locally
can assign values locally
can assign values locally...appended some string

7
@ Mahesh: perché ciò su cui fondamentalmente il modello si maschera è l'indirizzo di quel std::stringpuntatore o oggetto di riferimento. Se quella variabile fosse locale, potresti ottenere indirizzi diversi ogni volta che viene chiamata la funzione.
Xeo

11
@ Mahesh: Non sai come appare lo stack di chiamate in fase di compilazione. Prima della tua funzione, potevano essere chiamate altre 10 o altre 3 o comunque molte altre, quindi l'indirizzo sullo stack, in cui viene creata la stringa, può cambiare da chiamata a chiamata. Quando si dispone di un oggetto con collegamento esterno, il suo indirizzo viene corretto durante la compilazione / collegamento.
Xeo

2
@Xeo "il suo indirizzo è fisso durante la compilazione / collegamento. " Oppure no, per il codice rilocabile o indipendente dalla posizione.
Curiousguy

1
Questa risposta (attualmente) non sembra rispondere alla domanda dell'OP, che chiedeva perché esiste questo comportamento; questa risposta si limita a riaffermare l'esempio del PO senza offrire alcuna spiegazione.
Quuxplusone

1
Sono in ritardo per la festa, sembra che anche i puntatori intelligenti non funzionino
Nicholas Humphrey

28

Devi essere in grado di manipolare gli argomenti del modello

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"bar">(); // different function!?

Ora un impl dovrebbe creare una sequenza di caratteri univoca per una std::stringo, per quella materia, qualsiasi altra classe arbitraria definita dall'utente, memorizzando un valore particolare, il cui significato non è noto all'implementazione. Inoltre, il valore di oggetti di classe arbitrari non può essere calcolato in fase di compilazione.

Si prevede di considerare la possibilità di consentire tipi di classi letterali come tipi di parametri del modello per post-C ++ 0x, che vengono inizializzati da espressioni costanti. Questi potrebbero essere alterati facendo modificare ricorsivamente i membri dei dati in base ai loro valori (per le classi base, ad esempio, possiamo applicare la profondità prima, attraversamento da sinistra a destra). Ma sicuramente non funzionerà per classi arbitrarie.


10

Un argomento modello non di tipo fornito all'interno di un elenco di argomenti modello è un'espressione il cui valore può essere determinato in fase di compilazione. Tali argomenti devono essere:

espressioni costanti, indirizzi di funzioni o oggetti con collegamento esterno o indirizzi di membri di classi statiche.

Inoltre, i letterali stringa sono oggetti con collegamento interno, quindi non è possibile utilizzarli come argomenti del modello. Non è nemmeno possibile utilizzare un puntatore globale. I letterali in virgola mobile non sono consentiti, data l'ovvia possibilità di errori di arrotondamento.


Hai usato una citazione, quindi qual è la fonte? Mi piacerebbe votare se ha una fonte per la citazione.
Gabriel Staples il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.