问题描述
Scott Meyers 在 Effective Modern C++,Item 30 page 210 中写道,有
不需要在类中定义完整的static const
数据成员;仅声明就足够了,
那么示例代码是
class Widget {民众:静态常量 std::size_t MinVals = 28;//MinVals 的声明;...};...//没有定义.对于 MinValsstd::vector小部件数据;widgetData.reserve(Widget::MinVals);//使用 MinVals
我确信 static const std::size_t MinVals = 28;
是声明 也是 一个定义,因为它给出了MinVals
的值,但评论似乎声称这只是一个声明;第二条评论实际上声称没有定义.代码后面的文字,确实读起来
MinVals
缺少定义.
这证实了 static const std::size_t MinVals = 28;
不是定义,所以我有点困惑.
cppreference 对我帮助不大(我的粗斜体):
如果一个 static
整数或枚举类型的数据成员被声明 const
(而不是 volatile
),它可以用一个初始化器初始化,其中每个表达式都是一个常量表达式,就在类定义中:
struct X{const static int n = 1;const static int m{2};//从 C++11 开始const static int k;};const int X::k = 3;
但类中的前两行在我看来是定义.
以下 cppreference 示例也是如此:
struct X {静态常量 int n = 1;静态 constexpr int m = 4;};const int *p = &X::n, *q = &X::m;//X::n 和 X::m 是 odr 使用的const int X::n;//... 所以定义是必要的constexpr int X::m;//...(C++17 中的 X::m 除外)
我会说 static const int n = 1;
是一个定义,但它不是,基于倒数第二个评论.
仅当该对象未使用 ODR(即未使用数据成员)时,仅声明就足够了在需要其地址存在的上下文中(例如绑定到引用或应用运算符 &
).初始化器的存在不等于定义.
在书中的例子中,很明显 MinVals
不是 ODR 使用的,即编译器可以直接使用它的值,而不必在内存中创建一个对象,所以语句:
widgetData.reserve(Widget::MinVals);
变成:
widgetData.reserve(28);
但是,如果在任何其他地方,MinVals
被 ODR 使用,那将使程序格式错误.
cppreference 中的所有其他示例都清楚地说明了何时使用 ODR 且需要定义,何时不需要:
struct X{const static int n = 1;const static int m{2};//从 C++11 开始const static int k;};const int X::k = 3;
n
和 m
是带有初始化器的声明.尝试获取 n
或 m
的地址应该失败.
struct X {静态常量 int n = 1;静态 constexpr int m = 4;};const int *p = &X::n, *q = &X::m;const int X::n;constexpr int X::m;
表达式 &X::n
和 &X::m
算作 n
和 m 的 ODR 使用
,分别(即请求一个地址).对于 constexpr
静态数据成员,在 C++17 之前需要定义.从 C++17 开始,static constexpr
数据成员隐式地inline
,这意味着不需要类外定义,因为它们本身就是定义.
Scott Meyers writes in Effective Modern C++, Item 30 page 210, that there's
then the sample code is
class Widget {
public:
static const std::size_t MinVals = 28; // MinVals' declaration;
...
};
... // no defn. for MinVals
std::vector<int> widgetData;
widgetData.reserve(Widget::MinVals); // use of MinVals
I was convinced that static const std::size_t MinVals = 28;
is declaration and also a definition, as it is giving a value to MinVals
, but the comment seems to claim that's only a declaration; the second comment actually claims there's no definition. The text after the code, indeed reads
Which confirms that static const std::size_t MinVals = 28;
is not a definition, so I'm a bit confused.
cppreference doesn't help me much (my bold-italic):
but first two lines in the class look definitions to me.
The same goes for a following example on cppreference:
where I'd have said static const int n = 1;
is a definition, but it is not, based on the second to last comment.
Declarations alone suffice only if that object is not ODR-used, that is, if a data member is not used in a context that would require its address to exist (like binding to a reference or applying operator &
). The presence of an initializer does not equal a definition.
In the example from the book, it's clear that MinVals
is not ODR-used, i.e., the compiler can use its value directly, without having to create an object in memory, and so the statement:
widgetData.reserve(Widget::MinVals);
becomes:
widgetData.reserve(28);
If, however, in any other place, MinVals
were ODR-used, that would make the program ill-formed.
All other examples from cppreference clearly indicate when a value is ODR-used and a definition is required, and when not:
struct X
{
const static int n = 1;
const static int m{2}; // since C++11
const static int k;
};
const int X::k = 3;
n
and m
are declarations with initializers. An attempt to obtain the address of either n
or m
should fail.
struct X {
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m;
const int X::n;
constexpr int X::m;
Expressions &X::n
and &X::m
count as ODR-use of n
and m
, respectively (that is, an address is requested). For a constexpr
static data members, a definition was required prior to C++17. From C++17, static constexpr
data members are implicitly inline
, which means, no out-of-class definition is needed, as they are definitions themselves.
这篇关于关于静态常量数据成员的声明和定义的混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!