2015-01-16 12 views
5

Mam kilka stałych, które muszą być używane tylko w czasie kompilacji, aby uprościć kod, więc nie potrzebuję rzeczywistych zmiennych dostępnych w czasie wykonywania.Jak zdefiniować stałą czasu kompilacji (statyczną) wewnątrz klasy C++?

Tradycyjnie sposób, w jaki to zrobiono, był z #define NAME 123, ale chciałbym mieć opcję bezpieczną dla typu.

Poza zajęciami można const int name = 123; co działa dobrze, ale nie wydaje się możliwe umieszczenie tego wewnątrz klasy. Na przykład w ten sposób:

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

Works z Visual C++, ale nie działa z GCC:

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

można naprawić go przez co statyczne, ale potem Visual C++ narzeka:

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

Zgaduję, że oznacza to, że VC++ zaakceptuje tylko static const int.

Nie chcę ustawiać wartości w konstruktorze, ponieważ potrzebuję instancji klasy w środowisku wykonawczym, aby uzyskać dostęp do wartości, podczas gdy naprawdę chcę, aby wszystko było obsługiwane w czasie kompilacji, tak jak to jest z #define.

Jak więc zdefiniować stałą jako double w klasie, bez uciekania się do uczynienia jej globalną lub przy użyciu #define, która będzie działała bez instancji klasy, i która będzie działać z głównymi kompilatorami C++ 03 ?

Odpowiedz

10

Jest różnica pomiędzy tutaj integralnych i innych typów.Dla integralnych typach zawsze można je zdefiniować jako const static członków jak w

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

dla non-integralnych typów, takich jak double w przykładzie, sytuacja jest bardziej skomplikowana. Od 2011 roku (przy użyciu opcji kompilatora std=c++11 z większością kompilatorów), można po prostu to zrobić:

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

Ale z gcc, to

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

powinien działać również w C++ 03 (jest to rozszerzenie GNU).

Jednak standardowe podejście w C++ 03, który jest również wykorzystywany przez samego (na przykład w std::numeric_limits<>) biblioteki standardowej, jest funkcją static członkiem

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

'+ 1' dla wzmianki o' std :: numeric_limits <> ', uważam, że jest to przydatny punkt. – Angew

1

Ten kod działa zarówno na VC++ i gcc:

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

Widzę dwa możliwe podejścia z C++ 03:

  1. użyć statycznej funkcji członka i polegać na inline:

    class Example { 
        public: 
         static double usPerSec() { return 1000000.0; } 
    }; 
    double usOneMinute = 60 * Example::usPerSec(); 
    
  2. Użyj statycznego elementu danych i zrezygnuj ze stałego składania (wartość przy użyciu stałej będzie komp oddziaływał na starcie):

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

Druga opcja daje nierozwiązane zewnętrzne, jeśli używasz go w bibliotece i kompilujesz z MSVC++. Konieczność wyeksportowania symbolu w bibliotece DLL zdecydowanie przesadza ze względu na rzekomą stałą kompilacji, która normalnie nie byłaby widoczna poza biblioteką! – Malvineous

1

Musisz zrobić to const statyczny, a następnie nadać jej wartość spoza klasy. Nie rób tego wewnątrz konstruktora. Nie trzeba tworzyć instancji:

};

double Example::usPerSec = 1000000.0; 

Teraz można go używać w dowolnym miejscu bez dokonywania jakichkolwiek instancję klasy

double someVar = Example::usPerSec; 
2

Gdybym był tobą chciałbym umieścić to w przestrzeni nazw:

namespace MyExampleNamespace { 
    const double usPerSec = 1000000.0; 
} 
double usOneMinute = 60 * MyExampleNamespace::usPerSec; 
Powiązane problemy