如何在C++类中定义编译时(静态)常量?

5

我有一些常量,只需要在编译时使用以简化代码,因此我不需要在运行时可用的实际变量。

传统上,这是通过 #define NAME 123 来完成的,但我想要一个类型安全的替代方案。

在类的外部,您可以使用 const int name = 123;,这很好用,但似乎无法将其放在类内。例如:

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

可以与Visual C++一起使用,但无法与GCC一起使用:

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

您可以通过将其设置为静态来修复它,但是这时Visual C++会发出警告:

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

我猜这意味着VC++只接受“static const int”。 我想避免在构造函数中设置值,因为那样我需要在运行时拥有类的实例才能访问该值,而我真正想要的是像“#define”一样在编译时处理所有内容。 那么,如何在类内定义一个“double”常量,而不必将其设置为全局或使用“#define”,并且可以在没有类实例的情况下工作,并且可以与主要的C++03编译器一起使用?
5个回答

10

在这里,积分类型和其他类型之间存在差异。对于积分类型,您可以始终像下面这样将它们定义为const static成员

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

对于非整数类型,例如您示例中的double,情况会更加复杂。自2011年(使用大多数编译器的编译器选项std=c++11)以来,您可以简单地执行以下操作:

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

但是使用gcc,这个问题

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

应该也可以在C++03中工作(它是GNU扩展)。

然而,在C++03中,标准的方法也被标准库本身使用(例如在std::numeric_limits<>中),那就是一个static成员函数。

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

1
提到 std::numeric_limits<>,我觉得这是一个有用的点,值得加一。 - Angew is no longer proud of SO

4

我看到使用C++03有两种可能的方法:

  1. Use a static member function and rely on inlining:

    class Example {
        public:
            static double usPerSec() { return 1000000.0; }
    };
    double usOneMinute = 60 * Example::usPerSec();
    
  2. Use a static data member and resign on constant folding (the value using the constant will be computed at runtime):

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

如果您在库中使用第二个选项并使用MSVC++编译,则会出现未解决的外部符号。不得不在DLL中导出符号绝对是过度设计,因为这只是一个编译时常量,通常不会在库外可见! - Malvineous

2
如果我是你,我会把它放在一个命名空间中:
namespace MyExampleNamespace {
    const double usPerSec = 1000000.0;
}
double usOneMinute = 60 * MyExampleNamespace::usPerSec;

1
这段代码在vc++和gcc上都可以运行:
class Example {
public:
    static const double usPerSec ;
};
const double Example::usPerSec=10000.0;
double usOneMinute = 60 * Example::usPerSec;

1
你需要将其设置为静态常量,然后在类外给它赋值。不要在构造函数内部执行此操作。你不必创建实例。
class Example {
public:
    static const double usPerSec;

};

double Example::usPerSec = 1000000.0;

现在你可以在不创建任何类实例的情况下在任何地方使用它。
double someVar = Example::usPerSec;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接