2014-11-12 14 views
14

Come può il operator() di un lambda essere dichiarato come noreturn?Come dichiarare un operatore lambda() come noreturn?

Ideone accetta il seguente codice:

#include <cstdlib> 
int main() { 
    []() [[noreturn]] { std::exit(1); }(); 
    return 0; 
} 

Clang 3,5 respinge con:

error: 'noreturn' attribute cannot be applied to types 

Si può provare in Godbolt: http://goo.gl/vsuCsF

Quale è giusto?

Aggiornamento: le sezioni standard pertinenti sembrano essere 5.1.2.5, 7.6.3, 7.6.4 ma dopo la lettura non è ancora al 100% chiaro per me (i) qual è il comportamento corretto, (ii) come contrassegnare l'operatore() di una lambda come noreturn.

risposta

19

Clang è corretto. Un attributo può appartenere a una funzione dichiarata o al suo tipo; i due sono diversi. [[noreturn]] deve appartenere alla funzione stessa. La differenza può essere visto in

// [[noreturn]] appertains to the entity that's being declared 
void f [[noreturn]](); // §8.3 [dcl.meaning]/p1: 
          // The optional attribute-specifier-seq following a 
          // declarator-id appertains to the entity that is declared." 
[[noreturn]] void h(); // §7 [dcl.dcl]/p2: 
          // "The attribute-specifier-seq in a simple-declaration 
          // appertains to each of the entities declared by 
          // the declarators of the init-declarator-list." 

// ill-formed - [[noreturn]] appertains to the type (§8.3.5 [dcl.fct]/p1: 
// "The optional attribute-specifier-seq appertains to the function type.") 
void g() [[noreturn]] {} 

Infatti se si compila questo g ++ ti dice che

warning: attribute ignored [-Wattributes] 
void g() [[noreturn]] {} 
        ^
note: an attribute that appertains to a type-specifier is ignored 

Nota che non si emette un avvertimento che g() in realtà fa ritorno.

Poiché un "attributo-specificatore-seq nel lambda-declarator atterrebbe il tipo di modello operatore chiamata di funzione o dell'operatore corrispondente" (§5.1.2 [expr.prim.lambda]/P5) piuttosto che a quello stesso operatore/operatore, non è possibile utilizzare [[noreturn]] lì. Più in generale, la lingua non consente in alcun modo di applicare un attributo allo operator() di una lambda stessa.

+0

cioè, non c'è modo di usare attributi sull'operatore() di un lambda? – gnzlbg

+2

@gnzlbg No, non c'è modo. –

+0

@ T.C. C'è qualche ragione per questo, o il comitato non ci ha pensato. Ci sono state proposte per risolvere questo problema? – user877329

2

[C++11: 7.6.3/1]: Il attributo tokennoreturn specifica che una funzione non restituisce. Deve essere visualizzato al massimo una volta in ogni attributo e attributo-argomento-clausola deve essere presente. L'attributo può essere applicato all'identificatore in una dichiarazione di funzione. La prima dichiarazione di una funzione deve specificare l'attributo noreturn se qualsiasi dichiarazione di tale funzione specifica l'attributo noreturn. Se una funzione viene dichiarata con l'attributo noreturn in un'unità di traduzione e la stessa funzione viene dichiarata senza l'attributo noreturn in un'altra unità di traduzione, il programma è mal formato; nessuna diagnostica richiesta.

ho ammettono che questa formulazione, come è, non vieta l'attributo di apparire altrove, ma di concerto con vedendo alcuna prova in qualsiasi parte del standard per esso, io non credo che questo è destinato a lavorare con dichiarazioni lambda.

Pertanto, Clang sarebbe corretto.

Si può o non può essere dicendo che there was a patch proposal to Clang to allow GCC-style noreturn attributes on lambdas, ma non la forma standard.

Sfortunatamente, questa funzione non è inclusa in GCC's list of extensions, quindi non posso davvero vedere esattamente cosa sta succedendo qui.

+1

Da C++ 11 5.1.2.5: "Un identificatore di attributo-seq in un lambda-dichiaratore appartiene al tipo di operatore di chiamata di funzione corrispondente". Cioè, gcc ha ragione, penso. – gnzlbg

+0

@gnzlbg: Ciò significherebbe che GCC è sbagliato, no? –

+0

Lo capisco come un attributo in una lambda si riferisce all'operatore corrispondente(), quindi noreturn dovrebbe applicarsi all'operatore(), e non al tipo di lambda. – gnzlbg

4

Quindi un delcarator lambda ha il seguente grammatica del progetto C++ sezione standard 5.1.2Espressioni lambda:

(parameter-declaration-clause) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt 

e l'attributo noreturn è davvero una valida attributo specificatore-ss così dal punto di vista grammaticale Non vedo una limitazione dalla sezione 7.6.3Attributo Noreturn dice (enfasi miniera andando avanti):

[...] L'attributo può essere applicato al dichiaratore-id in una dichiarazione di funzione . [...]

che non sembra vietare l'utilizzo ma suggerisce che non è permesso. Se guardiamo alla sezione 7.6.4Trasporta dipendenza attributo dice:

[...] L'attributo può essere applicato al dichiaratore-id di un parametro di dichiarazione in una dichiarazione di funzione o lambda [ ...]

il fatto che include esplicitamente il caso Lamda indica fortemente che la sezione 7.6.3 si intende escludere lambda e quindi clang sarebbe corretto. Come nota a margine Visual Studio respinge anche questo codice.

+1

Da C++ 11 5.1.2.5: "Un attributo-specificatore-seq in un lambda-dichiaratore appartiene al tipo di operatore di chiamata di funzione corrispondente". Cioè, l'attributo [[noreturn]] sulla lambda si applica al tipo di operatore(). Non è necessario aggiungere specificamente 7.6.3 che si applica anche a un lambda. – gnzlbg

Problemi correlati