这就是我现在所拥有的:
class CColorf
{
public:
CColorf();
CColorf(float r, float g, float b, float a = 1.0f);
public:
float r, g, b, a;
// predefined colors
// rgb(0.0, 0.0, 1.0)
static const CColorf blue;
};
它适用于ccolorf.cpp中定义的blue
,如:
CColorf const CColorf::blue = CColorf(0.0f, 0.0f, 1.0f);
这就是我想做的事情:
class CColorf
{
...
// predefined colors
// rgb(0.0, 0.0, 1.0)
static const CColorf blue = CColorf(0.0f, 0.0f, 1.0f);
};
但它会产生编译错误:
具有类内初始化程序的静态数据成员必须具有非易失性const整数类型
有没有办法避免在这里需要单独的声明和定义?
答案 0 :(得分:3)
这里的经验法则是,如果成员变量static
(而不是const int
),则不能使用成员变量的类内成员初始化,但是有一些例外(仅适用于对你的情况而言)。
在C ++ 98标准中,您只能成员初始化static const int
在C ++ 11标准中,您可以成员初始化除static
之外的所有内容(C ++ 98标准除外)。
如果你的静态成员是constexpr
:
§9.4.2(2014年11月草案)
如果非易失性 const static 数据成员是整数或枚举类型,则其在类中的声明 定义可以指定大括号或等于初始值,其中每个 initializer-clause 是赋值表达式 是一个常数表达式(5.20)。可以在。中声明文字类型的静态数据成员 使用 constexpr 说明符的类定义;如果是这样,其声明应指定大括号或等于初始值 其中作为赋值表达式的每个 initializer-clause 都是一个常量表达式。 [注意:两者都有 在这些情况下,成员可能出现在常量表达式中。 - 尾注]成员仍应定义 如果在程序中使用odr-used(3.2)并且命名空间作用域定义不在,则在命名空间作用域中 包含初始值设定项。
更清楚地解释这个片段:
如果您想尝试使用constexpr
来解决问题,那么您的类型必须是“文字”。
文字类型(第3.9.10节):
void
,标量(例如int
),参考或文字类型数组如果出现以下情况,析构函数是“微不足道的”
鉴于所有这些,您可以查看您的代码并思考“嗯,我可以创建所有构造函数constexpr
,然后将static const CColorf blue
更改为static constexpr CColorf blue
和我“很好。”
但是,在声明静态时,您的课程“不完整”。让我们考虑以下example:
class A{
private:
A member;
}
A
的每个实例现在都有一个A
的实例。编译器为A
分配了多少字节?它无法分辨。也许,由于递归,无限多。 A在它自己的类中是不完整的。你有一个类似的不完整的问题。但是,让我们改为指针:
class A{
private:
A* member;
}
现在很容易,因为A*
是指针类型,编译器知道它的大小。
所以现在你想“好吧,我只会让static constexpr CColorf blue
指针static constexpr CColorf* blue = new CColorf(0.0f, 0.0f, 1.0f);
但你不能,因为new
运算符不是constexpr
。
你不能尝试const
因为我们已经解决了原因。
所以,您可能会考虑将new
运算符重载为constexpr
,但you can't do that either。
所以你运气不好。
答案 1 :(得分:1)
你做不到。
错误消息暗示您正在编译为C ++ 03,其中只能在其声明中初始化整数类型的常量静态成员;所以你不能为任何类类型做这个。
C ++ 11放宽了规则,但仍存在限制:
constexpr
来创建此类型的文字;但虽然第一点可以修复,而第三点只是限制你可以对成员做什么,而不是你是否可以定义它,第二点使它变得不可能。您必须以通常的方式在单个翻译单元中的类外定义变量。
如果要保留类定义中的所有内容以及可用于帮助编译时优化的值,可以定义函数而不是变量
static CColorf blue() {return CColorf(0.0f, 0.0f, 1.0f);}