2016-02-04 9 views
8

C++ 17 Aggiornamento: static constexpr variabili sono implicitamente inline quindi non è necessaria alcuna definizione esterna.Perché dovrei preferire il comando statico constexpr int in una classe su enum per le costanti integrali di livello di classe?


domanda originale:

Diciamo che ho una lista di costanti quali

struct Cls { 
    static constexpr int N = 32; 
    static constexpr int M = 64; 
}; 

Questo naturalmente suggerisce che aggiungo definizioni per questi per evitare problemi di ODR-utilizzo che possono verificarsi quindi ho bisogno:

constexpr int Cls::N; 
constexpr int Cls::M; 

Perché dovrebbe Io preferisco questo oltre

struct Cls { 
    enum : int { 
     N = 32, 
     M = 64 
    }; 
}; 

Il che mi fa risparmiare dei mal di testa ODR-utilizzo dal N e M sono più veramente solo costanti e non oggetti a se stanti (un affare più grande se questo è un colpo di testa-solo) ed è più breve. Potrei specificare esplicitamente il tipo enum : long long o qualsiasi altra cosa se necessario. Qual è il vantaggio del primo?

+0

Come scritto, 'N' e' M' sono di tipo anonimo 'enum', non di tipo' int'. Come dici tu, puoi specificare 'enum: int'; Ti suggerisco di farlo nel tuo esempio. –

+0

@KeithThompson done –

+0

@zenith la domanda in questo è "_non c'è modo di dire al compilatore che constexpr int SOME_VALUE = 27 significa che SOME_VALUE dovrebbe essere trattato solo come costante di tempo di compilazione e mai oggetto con linkage_ esterno" e questo è ciò che le risposte affrontano. Sto chiedendo se ci sia qualche vantaggio nell'usare 'static constexpr' invece di' enum's che mi motiverà a usarli per le costanti di livello di classe. –

risposta

3

Una differenza è che è possibile prendere l'indirizzo di uno static constexpr ma non di uno enum.

Un altro è che constexpr non è supportato dalle versioni precedenti del linguaggio (è stato introdotto in C++ 11).

Vorrei usare enum solo se i valori appartengono insieme. Darei anche allo enum un nome che descrive quella relazione. Non utilizzerei uno enum per definire costanti non correlate.

+0

Beh, sì, ma un buon compilatore eliminerà la lettura della memoria e userà l'indirizzamento in modalità immediata --- a meno che non si prenda l'indirizzo della costante, nel qual caso lo si forza per avere un indirizzo di memoria fisica. –

+2

@ PaulJ.Lucas Penso che stia dicendo che il 'static constexpr' ver è l'unica opzione se si vuole prendere l'indirizzo della costante –

2

Forse nessun vantaggio per l'utilizzo poiché si utilizzano solo valori interi fissi semplici.

Ma, [AFAIK] constexpr può essere più generale in quanto consente l'inizializzazione da tutto ciò che può essere valutato in fase di compilazione.

Da type_traits:

/// integral_constant 
    template<typename _Tp, _Tp __v> 
    struct integral_constant 
    { 
     static constexpr _Tp     value = __v; 
     typedef _Tp       value_type; 
     typedef integral_constant<_Tp, __v> type; 
     constexpr operator value_type() const { return value; } 
#if __cplusplus > 201103L 
#define __cpp_lib_integral_constant_callable 201304 
     constexpr value_type operator()() const { return value; } 
#endif 
    }; 

Così, constexpr ha l'utilizzo in metaprogrammazione.

Quanto segue è un po 'approssimativo.

Se si ha una funzione come:

constexpr unsigned 
bitmask(int bitno) 
{ 

    return 1u << bitno; 
} 

Si potrebbe trovare un uso come ad esempio:

constexpr unsigned BIT_0 = bitmask(0); 
constexpr unsigned BIT_1 = bitmask(1); 
+0

l'ultimo esempio funziona solo se' bitmask' è dichiarato come 'constexpr'. Sono a conoscenza dei vari usi di 'constexpr' non correlati a ciò che sto chiedendo. –

+0

Ho detto "un po 'rozzo" [ma sistemerò io]. Ma, se conosci gli altri usi di 'constexpr', non hai già risposto alla tua domanda? (es.) Hai delineato i problemi (ri ODR) e che puoi impostare il tipo 'enum'. Usa 'enum' [perché è più semplice] a meno che tu non sia possibile perché il rh è troppo complesso per' enum' [come in 'bitmask'] –

+1

La domanda è sul perché dovrei voler sostituire un' enum' con un 'constexpr 'per una costante intera in una classe. Se non c'è davvero alcun vantaggio (oltre ad avere un indirizzo) è anche bello. –

1

Sono abbastanza sicuro che ho intenzione di ottenere fiammato per questo, ma. ..

La ragione per cui vorrei darti è che l'uso di enum { } per costanti è un uso improprio del termine enum.Non stai enumerando nulla. È un uso improprio comune, concesso; ha i suoi vantaggi pratici; ma è semplicemente sbagliato. Ci dovrebbe essere un modo per dire "questa è solo una costante in fase di compilazione e nient'altro". anche il constexpr non è quella cosa, ma è più vicino dell'enum. Ed è giusto che non sia possibile enumare i valori in virgola mobile.

Detto questo, spesso uso le enumerazioni per le costanti.