首页 文章

在C语言中的类声明中初始化const成员

提问于
浏览
65

在PHP和C#中,常量可以在声明时初始化:

class Calendar3
{
    const int value1 = 12;
    const double value2 = 0.001;
}

我有一个仿函数的以下C声明,它与另一个类一起使用来比较两个数学向量:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }

    static const float tolerance = 0.001;
};

这个代码编译时没有问题 . 现在处于C 0x模式(-std = c 0x),g编译器输出一条错误消息:

错误:'constexpr'需要对非整数类型的静态数据成员'容差'进行类内初始化

我知道我可以在类定义之外定义和初始化这个 static const 成员 . 此外,可以在构造函数的初始化列表中初始化非静态常量数据成员 .

但有没有办法在类声明中初始化一个常量,就像在PHP或C#中可能的那样?

更新

我使用 static 关键字只是因为可以在g中的类声明中初始化这样的常量 . 我只需要一种方法来初始化类声明中的常量,无论它是否声明为 static .

6 回答

  • 1

    在C 11中,可以在类声明中初始化非 static 数据成员, static constexpr 数据成员和整数或枚举类型的 static const 数据成员 . 例如

    struct X {
        int i=5;
        const float f=3.12f;
        static const int j=42;
        static constexpr float g=9.5f;
    };
    

    在这种情况下,类 X 的所有实例的 i 成员由编译器生成的构造函数初始化为 5f 成员初始化为 3.12 . static const 数据成员 j 初始化为 42static constexpr 数据成员 g 初始化为 9.5 .

    由于 floatdouble 不是整数类型或枚举类型,因此这些成员必须是 constexpr 或非 static 才能允许类定义中的初始化程序 .

    在C 11之前,只有整数或枚举类型的 static const 数据成员可以在类定义中具有初始值设定项 .

  • 9

    初始化除const int类型之外的静态成员变量不是C 11之前的标准C . 除非指定 -pedantic 选项,否则gcc编译器不会向您发出警告(并生成有用的代码) . 然后你应该得到一个类似的错误:

    const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
    const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]
    

    这样做的原因是C标准没有规定应该如何实现浮点并留给处理器 . 为了解决这个问题和其他限制,引入了 constexpr .

  • -2

    是 . 只需添加 constexpr 关键字,如错误所示 .

  • 113

    如果您只需要在一个方法中使用它,则可以在本地静态声明它:

    struct equal_vec
    {
        bool operator() (const Vector3D& a, const Vector3D& b) const
        {
            static const float tolerance = 0.001f;
            Vector3D dist = b - a;
            return ( dist.length2() <= tolerance );
        }
    };
    
  • 1

    我遇到了这个问题,因为我需要使用相同的代码来编译不同版本的g(GNU C编译器) . 所以我不得不使用一个宏来查看正在使用哪个版本的编译器,然后相应地采取行动,就像这样

    #if __GNUC__ > 5
     #define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
    #else
     #define GNU_CONST_STATIC_FLOAT_DECLARATION const
    #endif
    
    GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;
    

    这将在g版本6.0.0之前的所有内容中使用'const',然后在g版本6.0.0及更高版本中使用'constexpr' . 这是对发生变化的版本的猜测,因为坦白说我直到g版本6.2.1才注意到这一点 . 要做得对,你可能需要查看g的次要版本和补丁号,所以请参阅

    https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

    有关可用宏的详细信息 .

    使用gnu,你也可以坚持使用'const'无处不在,然后使用 -fpermissive 标志进行编译,但这会发出警告,我喜欢我的东西来干净地编译 .

    不是很好,因为它特定于gnu编译器,但我怀疑你可以和其他编译器做类似的事情 .

  • 42

    那么,不完全是一个直接的答案,但任何特定的原因不使用宏?

    #define tolerance 0.001
    struct equal_vec
    {
        bool operator() (const Vector3D& a, const Vector3D& b) const
        { 
            Vector3D dist = b - a;
            return ( dist.length2() <= tolerance );
        }
    };
    

    不完全是好的C#练习,但恕我直言在C中完全合法 .

相关问题