2015-01-16 22 views
5

Ho alcune costanti che devono essere utilizzate solo in fase di compilazione per semplificare il codice, quindi non ho bisogno delle variabili attuali disponibili in fase di esecuzione.Come definire la costante (statica) di compilazione all'interno di una classe C++?

Tradizionalmente il modo in cui questo è stato fatto era con #define NAME 123 ma vorrei un'alternativa sicura al tipo.

Al di fuori delle classi è possibile const int name = 123; che funziona bene, ma non sembra possibile inserirlo all'interno di una classe. Per esempio, questo:

class Example { 
    public: 
     const double usPerSec = 1000000.0; 
}; 
double usOneMinute = 60 * Tempo::usPerSec; 

Opere con Visual C++, ma non funziona con GCC:

error: non-static const member ‘const double Example::usPerSec’, 
    can’t use default assignment operator 

È possibile risolvere il problema, rendendo più statico, ma poi di Visual C++ si lamenta:

error C2864: 'Example::usPerSec' : a static data member with an in-class 
    initializer must have non-volatile const integral type 
    type is 'const double' 

Suppongo che questo significhi che VC++ accetterà solo static const int.

Voglio evitare di impostare il valore nel costruttore perché quindi ho bisogno di un'istanza della classe in fase di esecuzione per accedere al valore, mentre in realtà voglio che tutto venga gestito in fase di compilazione come lo è con #define.

Quindi, come posso definire una costante come double all'interno di una classe, senza ricorrere a renderla globale o usando #define, che funzionerà senza avere un'istanza della classe, e che funzionerà con i principali compilatori C++ 03 ?

risposta

10

C'è una differenza qui tra i tipi integrali e altri.Per i tipi integrali si può sempre definire const static membri come in

struct Example 
{ 
    const static int name = 123; // added 'static' to code in text of question 
    const static unsigned usPerSec = 1000000; 
}; 

Per i tipi non integrali, come ad esempio double nel tuo esempio, la situazione è più complicata. Dal 2011 (utilizzando l'opzione del compilatore std=c++11 con la maggior parte dei compilatori), si può semplicemente fare questo:

struct Example 
{ 
    constexpr static double usPerSec = 1000000.0; 
}; 

Ma con gcc, questo

struct Example 
{ 
    const static double usPerSec = 1000000.0; 
}; 

dovrebbe funzionare anche in C++ 03 (si tratta di un'estensione GNU).

Tuttavia, l'approccio standard in C++ 03, che è anche utilizzato dalla libreria standard in sé (per esempio in std::numeric_limits<>), è una funzione static membro

struct Example 
{ 
    static double usPerSec() { return 1000000.0; } 
}; 
+1

'+ 1' per aver menzionato' std :: numeric_limits <> ', ritengo che sia un punto utile. – Angew

1

Questo codice funziona sia su VC++ e gcc:

class Example { 
public: 
    static const double usPerSec ; 
}; 
const double Example::usPerSec=10000.0; 
double usOneMinute = 60 * Example::usPerSec; 
4

vedo due possibili approcci con C++ 03:

  1. utilizzare una funzione membro statica e si basano su inlining:

    class Example { 
        public: 
         static double usPerSec() { return 1000000.0; } 
    }; 
    double usOneMinute = 60 * Example::usPerSec(); 
    
  2. Utilizzare un membro dati statici e dimettersi su piegatura costante (il valore utilizzando la costante sarà comp buito in fase di esecuzione):

    class Example { 
        public: 
         static const double usPerSec; 
    }; 
    double usOneMinute = 60 * Example::usPerSec; 
    
    // Somewhere in one .cpp 
    const double Example::usPerSec = 1000000.0; 
    
+0

La seconda opzione fornisce elementi esterni non risolti se la si utilizza in una libreria e si compila con MSVC++. Dovendo esportare il simbolo in una DLL è sicuramente eccessivo per una presunta costante in fase di compilazione che normalmente non sarebbe visibile all'esterno della libreria! – Malvineous

1

Bisogna rendere static const e poi dare valore al di fuori della classe. Non farlo all'interno del costruttore. Non è necessario creare l'istanza

class Example { 
public: 
    static const double usPerSec; 

};

double Example::usPerSec = 1000000.0; 

Ora si può usare ovunque senza fare alcuna istanza della classe

double someVar = Example::usPerSec; 
2

Se fossi in te avrei messo in uno spazio dei nomi:

namespace MyExampleNamespace { 
    const double usPerSec = 1000000.0; 
} 
double usOneMinute = 60 * MyExampleNamespace::usPerSec; 
Problemi correlati