Perché i lambda generici sono permessi mentre le strutture annidate con metodi basati su modelli non lo sono?

Per quel che ne so – i lambdas generici vengono trasformati in oggetti di strutture locali di scope con operator() template operator() . Questo rende lambda generico strumento molto potente e facile da usare. D’altra parte è ansible creare strutture nidificate nella funzione, quando tuttavia la struttura ha un membro di modello ad esempio:

 #include  int main() { struct inner { template  void operator()(T &&i) { } }; return 0; } 

o è rappresentato da solo:

 int main() { template  struct inner { void operator()(T &&i) { } }; return 0; } 

il compilatore sembra avere un problema con la sua compilazione:

 error: invalid declaration of member template in local class 

e

 error: a template declaration cannot appear at block scope 

Presumo che il problema risieda più nello standard c ++ che nel bug del compilatore. Quali sono le ragioni per cui a lambdas è permesso avere membri di un gruppo e non le strutture locali?

Ho trovato questa qustion , ma penso che la risposta sia un po ‘obsoleta (non penso sia vero nemmeno per il c ++ 11).

Questo è il nocciolo 728 , che è stato archiviato prima che i lambda generici fossero una cosa.

Hai citato i lambda generici e che erano identici alle classi locali con l’ template operator() membro corrispondente template operator() . Tuttavia, in realtà non lo sono, e le differenze sono legate alle caratteristiche di implementazione. Tenere conto

 template  class X { template  void foo() { T t; } }; 

E

 template  auto bar() { return [] (auto) {T t;}; }; 

L’istanziazione di questi modelli con andrà bene nel primo caso, ma mal formata nel secondo. Perché bene nel primo caso? foo non ha bisogno di essere istanziabile per ogni T particolare, ma solo uno di questi (questo sarebbe [temp.res] / (8.1) ).

Perché mal formato nel secondo caso? Il corpo del lambda generico viene istanziato – in parte – utilizzando gli argomenti del modello forniti. E la ragione di questa parziale istanziazione è il fatto che …

… gli ambiti lessicali utilizzati durante l’elaborazione di una definizione di funzione sono fondamentalmente transitori, il che significa che è difficile supportare l’istanziazione ritardata di una parte della definizione di un modello di funzione.

( Richard Smith ) È necessario creare un’istanza sufficiente del “template” locale per renderlo indipendente dal contesto locale (che include i parametri del template del modello di funzione che lo racchiude).

Questo è anche legato alla logica di [expr.prim.lambda] / 13 , che impone che un’ quadro venga catturata implicitamente da una lambda se …

denomina l’ quadro in un’espressione potenzialmente valutata ([basic.def.odr]) in cui l’ espressione completa che la racchiude dipende da un parametro lambda generico dichiarato nell’ambito di portata dell’espressione lambda .

Cioè, se ho un lambda come [=] (auto x) {return (typename decltype(x)::type)a;} , dove a è una variabile block-scope da una funzione di inclusione, indipendentemente dal fatto che x ‘ Il membro s typedef è void o no, il cast causerà una cattura di a , perché dobbiamo decidere su questo senza aspettare un’invocazione del lambda. Per una discussione di questo problema, vedere la proposta originale sui lambda generici .

La linea di fondo è che la creazione di istanze completamente posticipata di un modello membro non è compatibile con il modello utilizzato da (almeno una) implementazione principale (s), e poiché queste sono la semantica prevista, la funzione non è stata introdotta.


Era questa la motivazione originale per questo vincolo? È stato introdotto tra gennaio e maggio 1994, senza carta che lo copra, quindi possiamo solo avere un’idea approssimativa delle nozioni prevalenti dalla giustificazione del motivo per cui le classi locali non devono essere argomenti del modello:

I modelli di class e le classi generate dal modello sono quadro di ambito globale e non possono fare riferimento a entity framework di ambito locale.

Forse allora, uno voleva KISS.

Presumo che il problema risieda maggiormente nello standard c ++

Corretta. Questo è stabilito in [temp] per i modelli di class:

Una dichiarazione modello può apparire solo come ambito dello spazio dei nomi o dichiarazione dell’ambito della class.

e [temp.mem] per i modelli dei membri:

Una class locale di tipo non-closure non deve avere modelli membri.


Quali sono le ragioni per cui a lambdas è permesso avere membri di un gruppo e non le strutture locali?

Perché una volta che abbiamo avuto lambda in C ++ 11, si è ritenuto che sarebbe estremamente utile estendere tale concetto per avere lambda generici. C’era una proposta per tale estensione linguistica, che è stata rivista, rivista e adottata.

D’altra parte, non è stata ancora presentata una proposta (per quanto ne so da una breve ricerca) che espone la motivazione per la necessità di modelli di membri nelle classi locali che non siano adeguatamente risolti da un lambda generico .

Se ritieni che questo sia un problema importante che deve essere risolto, sentiti libero di presentare una proposta dopo aver express una motivazione per il motivo per cui i modelli di membri locali sono importanti.