2015-06-05 8 views
6

Ho notato che è consentito utilizzare le caratteristiche di tempo di compilazione delle variabili che non sono state catturate in lambda, ad es. chiamare sizeof, decltype funzioni, ad esempio:Qual è il punto di essere in grado di utilizzare le caratteristiche di compilazione di variabili locali non acquisite in una lambda?

#include <iostream> 
void f() 
{ 
} 

int main() 
{ 
    int y = 13; 
    auto x = []{ return sizeof (decltype (y));}; 
    std::cout << x() << '\n'; 
} 

quanto sia g++ e clang++ compilare questo programma senza errori Credo che sia consentito dalla norma.

Mi sembra un po 'fuorviante anche se non riesco a pensare a nessun caso malevolo particolare in cui porterà a un errore. Ma mi chiedo quali sono i casi d'uso reali di questa funzionalità?

+3

Più in generale, è necessario acquisire le variabili locali solo se sono * odr-used *. Ad esempio, puoi usare il valore delle variabili locali 'constexpr' come' constexpr int x = 42; '. – dyp

+0

Sembra abbastanza ragionevole per me, non vorrei avere variabili che non accedo allo scope capture. –

+0

Quali sono i reali casi d'uso di un mattone da costruzione? –

risposta

5

Un semplice esempio in cui è possibile utilizzare questo è se si dispone di una lambda in cui si desidera eseguire calcoli dello stesso tipo di , poiché verrà assegnato il risultato a y.

Inoltre, pensate al contrario: qual è il vantaggio di acquisire in [=]{ return x + sizeof (y);}? Non ha assolutamente senso farlo, dal momento che lo non viene effettivamente utilizzato all'interno della lambda. Catturare aggiungerebbe semplicemente un sovraccarico completamente inutile. Non solo, potrebbe anche complicare il funzionamento interno dei compilatori, dal momento che non sarebbero più in grado di ottimizzare semplicemente , sizeof(y) non è più semanticamente equivalente a sizeof(int).

+0

OK, quindi per quanto ho capito se si acquisisce la variabile in base al riferimento e in seguito verrà esclusa dall'ambito, mentre in questo caso non si aggiungerà alcun sovraccarico, si rischia di utilizzare questa variabile all'interno di lambda quando è già andato fuori portata. Quindi questo è probabilmente il ragionamento giusto. – Predelnik

0

A volte in uno scope nidificato (lambda) è necessario digitare le informazioni senza il valore. Puoi sempre dare un nome al tipo (o al parametro del modello) direttamente se hai accesso ad esso, ma c'è sempre quella leggenda metropolitana un buon consiglio che dice che se un giorno cambi il tipo di variabile non dovrai cambiarlo in tutte le altre espressioni in cui lo hai ripetuto.

Ad esempio:

#include <iostream> 
#include <tuple> 
#include <utility> 

class storage 
{ 
public: 
    template<typename T> 
    auto make_getter(T value) 
    { 
    std::get<decltype(value)>(storage_) = value; 

    auto getter = [this] 
     { 
     return std::get<decltype(value)>(storage_); 
     }; 

    return getter; 
    } 

private: 
    std::tuple<int, char, double> storage_; 
}; 

int  main(void) 
{ 
    storage  s; 

    auto getter = s.make_getter(42); 

    std::cout << getter() << std::endl; 
} 

Qui si può sempre utilizzare std::get<T> invece di std::get<decltype(value)> ma se un giorno make_getter non è un modello più e diventa una funzione normale sovraccarico per ogni tipo di tupla rispetto al tipo di valore ad esempio, ilfunzionerà sempre se non si rinomina la variabile.

In ogni caso, penso che il livello di utilità di questa funzione potrebbe essere più semantico che tecnico. Questo comportamento è probabilmente ereditata dalla vecchia scuola canonica

char *buffer = malloc(42 * sizeof(*buffer)); 

utilizzato nel C lingua invece di

char *buffer = malloc(42 *sizeof(char)); 

per le stesse ragioni.

Anche se il nome del tipo è qualcosa di insopportabile che non si desidera l'alias per qualche motivo si va in decltype che non significa necessariamente che si desidera il valore associato.

Problemi correlati