2016-05-24 10 views
7

ho a che fare con un po 'di codice C che prende alcuni dati, e l'inoltra alla funzione passata:I miei parametri lambda ombreggiano davvero la mia gente del posto?

void foo(int* data, void (*fun)(int*)){ 
    (*fun)(data); 
}; 

I seguenti lavori senza preavviso:

void bar(int* data){}; 

int main(){ 
    int data=0; 
    foo(&data,bar); 
} 

Tuttavia, se uso un lambda invece:

int main(){ 

    int data=0; 
    foo(&data,[](auto data){}); 
} 

ottengo il seguente avvertimento:

warning: declaration of ‘data’ shadows a previous local [-Wshadow] 
    foo(&data,[](auto data){}); 
         ^
o.cpp:14:7: note: shadowed declaration is here 
    int data=0; 

Ma ho pensato che un gruppo di acquisizione vuoto avrebbe escluso la prima istanziazione durante la sua ricerca.

Questo avviso è legittimo?
Perché la cattura vuota non è sufficiente per evitare avvisi?

+0

Penso che l'avviso sia solo lì per avvertirti che potresti aver pensato che stavi usando 'data' e non' data'. Non sa quale sia il tuo * intento *. – vu1p3n0x

+3

Il _name_ è effettivamente ombreggiato. Non è necessario acquisire un simbolo per utilizzare il suo nome, ad es. in un contesto non valutato come 'decltype'. – ildjarn

+0

Almeno in Visual Studio 2015 * non è possibile * utilizzare i simboli in un contesto non valutato (anche decltype (data) o sizeof (dati) non riescono con un errore 'C2065: 'identificativo non dichiarato' dati ') –

risposta

4

I nomi dall'ambito di inclusione del lambda sono anche nell'ambito della lambda.

I nomi che non vengono acquisiti possono ancora essere utilizzati, a condizione che non siano odr-used. Solo le variabili odr-used devono essere catturate. Esempio:

#include <iostream> 

template<typename T> void foo(const int *, T f) { std::cout << f(5) << '\n'; } 

int main() 
{ 
    const int data=0; 
    foo(&data,[](int baz){ 
     return data; 
    }); 
} 

Poiché la lettura un'espressione costante non è ODR-uso, questo codice è corretto e data fa riferimento alla variabile in main.

Questo programma emette 0, ma se si modifica int baz a int data, viene emesso 5.

+0

Un elenco di acquisizione vuoto non cattura qualsiasi variabile dall'ambito corrente (vedi qui http://en.cppreference.com/w/cpp/language/lambda). Visual Studio 2015 non compila il tuo esempio e fallisce con l'errore C3493 (nessuna acquisizione implicita di "data" se non viene fornito il tipo di cattura predefinito) –

+0

@AndreasH Il punto della mia risposta è che quei nomi sono in ambito e possono essere utilizzati in modi limitati anche se non vengono catturati –

+0

Ciò significherebbe che potrei scrivere [] (int baz) { return sizeof (data);} perché questo non è un odr-uso dei dati (quindi nessuna acquisizione necessaria) e dovrebbe essere ancora nell'ambito di lambda - o mi manca qualcosa? –

0

In riferimento a MISRA C++ 2008: Un identificatore dichiarato in un ambito interno non deve mai avere lo stesso nome di un identificatore dichiarato nell'ambito esterno.

Nell'esempio int data viene dichiarato nell'ambito esterno ma passa all'ambito interno della lambda tramite riferimento. Il problema è che hai anche un parametro nella lista dei parametri del tuo lambda chiamato data (scope interno). Ciò porta a nascondere la variabile dei dati dall'ambito esterno all'interno della lambda.

A proposito. Anche il tuo primo esempio con il puntatore a funzione dovrebbe essere riscritto perché esiste anche un conflitto con la denominazione degli identificatori in ambito interno ed esterno. In questo caso non è veramente male perché efficace c'è solo una variabile di dati in uso all'interno del punteggio interno. Tuttavia, quando le variabili di lista dei parametri e le variabili dall'ambito esterno che chiama la funzione hanno lo stesso nome, ciò potrebbe portare a confusione dei programmatori e dovrebbe anche essere evitato.

Problemi correlati