Lambda captureless è garantito per essere vuoto dallo standard?


12

Sto cercando un modo per identificare lambda vuote (senza capotasto) da altre lambda in una funzione modello. Attualmente sto usando C ++ 17 ma sono curioso anche per le risposte C ++ 20.

Il mio codice è simile al seguente:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

È garantito dallo standard C ++ (17 o 20) che anche un lambda senza cattura, che è convertibile in un puntatore a funzione, renderà std::is_emptyvero il rendimento?

Prendi questo codice come esempio:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

Esempio dal vivo


2
Se ti interessa solo lambda non template, puoi usare SFINAE per verificare se la conversione in un puntatore a funzione ( +lambda) è ben formata.
HolyBlackCat

@HolyBlackCat Ci ho pensato, ma per quanto mi ricordo, MSVC non lo consente poiché ha sovraccaricato l'operatore di conversione.
Guillaume Racicot,

@GuillaumeRacicot MS espone un operatore di conversione separato per tutte le convenzioni di chiamata disponibili. Basta sceglierne uno e provare a convertire lambda in un puntatore a funzioni comparabili e verificare se ha esito positivo o negativo.
Remy Lebeau,

+sembra funzionare qui .
HolyBlackCat

Risposte:


13

No, infatti, lo standard concede esplicitamente l'autorizzazione per lambdas ad avere una dimensione che non si allinea alla loro dichiarazione. [expr.prim.lambda.closure] / 2 stati

Il tipo di chiusura è dichiarato nell'ambito di blocco, ambito di classe o ambito di spazio dei nomi più piccolo che contiene l'espressione lambda corrispondente. [Nota: questo determina l'insieme di spazi dei nomi e classi associati al tipo di chiusura ([basic.lookup.argdep]). I tipi di parametro di un lambda-dichiaratore non influiscono su questi spazi dei nomi e classi associati. - end note] Il tipo di chiusura non è un tipo aggregato. Un'implementazione può definire il tipo di chiusura in modo diverso da quanto descritto di seguito, a condizione che ciò non alteri il comportamento osservabile del programma se non modificando:

  • la dimensione e / o l'allineamento del tipo di chiusura,

  • se il tipo di chiusura è banalmente copiabile ([class.prop]) o (2.3)

  • se il tipo di chiusura è una classe di layout standard ([class.prop]).

Un'implementazione non deve aggiungere membri del tipo di riferimento del valore al tipo di chiusura.

enfatizzare il mio

Ciò consente quindi all'implementazione di dare un membro lambda anche se è privo di acquisizione. Non credo che nessuna implementazione lo farebbe mai, ma è legalmente autorizzato a farlo.

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.