c++ - library - download clang compiler for mac



Cattura lambda e parametro con lo stesso nome: chi ombreggia l'altro?(clang vs gcc) (2)

auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
  • clang ++ 3.6.0 e versioni successive stampa "Stai usando clang ++!" e avvisa che la cattura non è stata utilizzata.

  • g ++ 4.9.0 e versioni successive stampa "Stai usando g ++!" e avvisa che il parametro foo non viene utilizzato.

Quale compilatore sta seguendo più accuratamente lo standard C ++ qui?

esempio di wandbox

https://src-bin.com


Answer #1

Aggiornamento: come promesso dalla cattedra Core nella citazione in basso, il codice è ora mal formato :

Se un identificatore in una cattura semplice appare come ID dichiaratore di un parametro della clausola-dichiarazione- parametro del lambda-dichiaratore , il programma è mal formato.

Qualche tempo fa c'erano alcuni problemi riguardanti la ricerca dei nomi in lambdas. Sono stati risolti da N2927 :

La nuova formulazione non si basa più sulla ricerca per rimappare gli usi delle entità acquisite. Nega più chiaramente le interpretazioni che un'istruzione composta di lambda viene elaborata in due passaggi o che i nomi in tale istruzione composta potrebbero risolversi in un membro del tipo di chiusura.

La ricerca viene sempre eseguita nel contesto dell'espressione lambda , mai "dopo" la trasformazione nel corpo della funzione membro di un tipo di chiusura. Vedi [expr.prim.lambda]/8 :

L' istruzione composta dell'espressione lambda produce il corpo-funzione ([dcl.fct.def]) dell'operatore di chiamata della funzione, ma ai fini della ricerca del nome, […], l' istruzione composta viene considerata nel contesto di l' espressione lambda . [ Esempio :

struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x+y);  // equivalent to: S1::operator()(this->x+(*this).y)
                                     // and this has type S1*
    }; 
  }
};

- fine esempio ]

(L'esempio chiarisce inoltre che la ricerca non considera in qualche modo il membro di acquisizione generato del tipo di chiusura.)

Il nome foo non viene (ri) dichiarato nella cattura; è dichiarato nel blocco che racchiude l'espressione lambda. Il parametro foo è dichiarato in un blocco nidificato in quel blocco esterno (vedere [basic.scope.block]/2 , che menziona esplicitamente anche i parametri lambda). L'ordine di ricerca è chiaramente dai blocchi interni a quelli esterni . Quindi il parametro dovrebbe essere selezionato, cioè Clang ha ragione.

Se dovessi rendere la cattura una init-capture, ovvero foo = "" anziché foo , la risposta non sarebbe chiara. Questo perché l'acquisizione ora induce effettivamente una dichiarazione il cui "blocco" non viene dato. Ho mandato un messaggio alla sedia principale su questo, che ha risposto

Questo è il numero 2211 (un nuovo elenco di numeri apparirà sul sito open-std.org a breve, sfortunatamente con solo segnaposto per una serie di problemi, di cui questo è uno; sto lavorando sodo per colmare quelle lacune prima della Kona incontro alla fine del mese). CWG ne ha discusso durante la nostra teleconferenza di gennaio e la direzione è di rendere il programma mal formato se un nome di acquisizione è anche un nome di parametro.


Answer #2

Sto cercando di mettere insieme alcuni commenti alla domanda per darti una risposta significativa.
Prima di tutto, nota che:

  • I membri di dati non statici vengono dichiarati per la lambda per ogni variabile acquisita per copia
  • Nel caso specifico, il lambda ha un tipo di chiusura che ha un operatore di chiamata di funzione di modello inline pubblico che accetta un parametro chiamato foo

Pertanto la logica mi farebbe dire a prima vista che il parametro dovrebbe oscurare la variabile acquisita come se in:

struct Lambda {
    template<typename T> void operator()(T foo) const { /* ... */ }
    private: decltype(outer_foo) foo{outer_foo};
};

Ad ogni modo, @nm ha osservato correttamente che i membri di dati non statici dichiarati per le variabili acquisite con copia sono effettivamente senza nome. Detto questo, al membro di dati senza nome è ancora possibile accedere tramite un identificatore (ovvero foo ). Pertanto, il nome del parametro dell'operatore di chiamata della funzione dovrebbe ancora (per così dire) ombreggiare quell'identificatore .
Come correttamente sottolineato da @nm nei commenti alla domanda:

l'entità acquisita originale [...] dovrebbe essere ombreggiata normalmente secondo le regole dell'ambito

Per questo motivo, direi che clang ha ragione.





shadowing