Unscoped enumerators within a class definition - c++

As known, static data members shall not be defined in the class definition:
N4296:9.4.2/2 [class.static.data]
The declaration of a static data member in its class definition is not
a definition and may be of an incomplete type other than cv-qualified
void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition.
Consider the following class:
#include <iostream>
struct A
{
enum E { x = 2, y = 3 }; //both enuerators are defined in the definition of `A`
};
int x = A::x; //looks like A::x is static data member, despite being defined in the scope of `A`
int main(){ std::cout << x << std::endl; }
DEMO
In the example all the enumerators were declared within the class scope, actually:
N4296::7.2/11 [dcl.enum]
Each enum-name and each unscoped enumerator is declared in the scope
that immediately contains the enum-specifier.
So, it's not clear unscoped enumerators are static or non-static data members. We can use them outside of an object-expression, therefore they should be static. On the other hand, we can't define static data members in a class scope. It looks a bit contradictory to me, couldn't you clarify that?

In your example, A::x is not a data member at all. It has no storage. To prove this to yourself, try taking its address: you can't.

[class.mem]/p1:
Members of a class are data members, member functions (9.3), nested
types, and enumerators.
Enumerators are not data members.

Related

c++ terminology 2 part question reguarding "declaring" vs "initializing" variables [duplicate]

After reading the question, I know the differences between declaration and definition. So does it mean definition equals declaration plus initialization?
Declaration
Declaration, generally, refers to the introduction of a new name in the program. For example, you can declare a new function by describing it's "signature":
void xyz();
or declare an incomplete type:
class klass;
struct ztruct;
and last but not least, to declare an object:
int x;
It is described, in the C++ standard, at §3.1/1 as:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
Definition
A definition is a definition of a previously declared name (or it can be both definition and declaration). For example:
int x;
void xyz() {...}
class klass {...};
struct ztruct {...};
enum { x, y, z };
Specifically the C++ standard defines it, at §3.1/1, as:
A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function- body, it declares a static data member in a class definition (9.2, 9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), it is a template-parameter (14.1), it is a parameter-declaration (8.3.5) in a function declarator that is not the declarator of a function-definition, or it is a typedef declaration (7.1.3), an alias-declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute- declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).
Initialization
Initialization refers to the "assignment" of a value, at construction time. For a generic object of type T, it's often in the form:
T x = i;
but in C++ it can be:
T x(i);
or even:
T x {i};
with C++11.
Conclusion
So does it mean definition equals declaration plus initialization?
It depends. On what you are talking about. If you are talking about an object, for example:
int x;
This is a definition without initialization. The following, instead, is a definition with initialization:
int x = 0;
In certain context, it doesn't make sense to talk about "initialization", "definition" and "declaration". If you are talking about a function, for example, initialization does not mean much.
So, the answer is no: definition does not automatically mean declaration plus initialization.
Declaration says "this thing exists somewhere":
int foo(); // function
extern int bar; // variable
struct T
{
static int baz; // static member variable
};
Definition says "this thing exists here; make memory for it":
int foo() {} // function
int bar; // variable
int T::baz; // static member variable
Initialisation is optional at the point of definition for objects, and says "here is the initial value for this thing":
int bar = 0; // variable
int T::baz = 42; // static member variable
Sometimes it's possible at the point of declaration instead:
struct T
{
static int baz = 42;
};
…but that's getting into more complex features.
For C, at least, per C11 6.7.5:
A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant, is the (only) declaration of the identifier;
for a typedef name, is the first (or only) declaration of the identifier.
Per C11 6.7.9.8-10:
An initializer specifies the initial value stored in an object ... if
an object that has automatic storage is not initialized explicitly,
its value is indeterminate.
So, broadly speaking, a declaration introduces an identifier and provides information about it. For a variable, a definition is a declaration which allocates storage for that variable.
Initialization is the specification of the initial value to be stored in an object, which is not necessarily the same as the first time you explicitly assign a value to it. A variable has a value when you define it, whether or not you explicitly give it a value. If you don't explicitly give it a value, and the variable has automatic storage, it will have an initial value, but that value will be indeterminate. If it has static storage, it will be initialized implicitly depending on the type (e.g. pointer types get initialized to null pointers, arithmetic types get initialized to zero, and so on).
So, if you define an automatic variable without specifying an initial value for it, such as:
int myfunc(void) {
int myvar;
...
You are defining it (and therefore also declaring it, since definitions are declarations), but not initializing it. Therefore, definition does not equal declaration plus initialization.
"So does it mean definition equals declaration plus initialization."
Not necessarily, your declaration might be without any variable being initialized like:
void helloWorld(); //declaration or Prototype.
void helloWorld()
{
std::cout << "Hello World\n";
}

Class static variable initialization order

I have a class A which has two static variables. I'd like to initialize one with another, unrelated static variable, just like this:
#include <iostream>
class A
{
public:
static int a;
static int b;
};
int A::a = 200;
int a = 100;
int A::b = a;
int main(int argc, char* argv[])
{
std::cout << A::b << std::endl;
return 0;
}
The output is 200. So, could anyone tell me why?
That's correct according to the lookup rules. [basic.lookup.unqual]/13 says:
A name used in the definition of a static data member of class X
(after the qualified-id of the static member) is looked up as if the
name was used in a member function of X. [ Note: [class.static.data]
further describes the restrictions on the use of names in the
definition of a static data member.  — end note ]
Since the unqualified a is looked up as if you are inside a member function, it must find the member A::a first. The initialization order of A::a and A::b doesn't affect the lookup, though it affects how well defined the result is.
So, could anyone tell me why?
This is clearly stated in basic.scope.class/4, emphasis mine:
The potential scope of a declaration that extends to or past the end
of a class definition also extends to the regions defined by its
member definitions, even if the members are defined lexically outside
the class (this includes static data member definitions, nested class
definitions, and member function definitions, including the member
function body and any portion of the declarator part of such
definitions which follows the declarator-id, including a
parameter-declaration-clause and any default arguments).
Thus, when you have
int A::a = 200;
int a = 100;
int A::b = a; // note the '::' scope resolution operator
// OUTPUT: 200
a actually refers to A::a because the class scope is extended by A::b.
Unlike if you have:
int A::a = 200;
int a = 100;
int b = a; // note b is not A::b
// i.e. without the '::', scope resolution operator
// OUTPUT: 100
a would refer to the (global) ::a since b here is not a member of class A,i.e. no class scope extension.
c++draft/class.static
If an unqualified-id is used in the definition of a static member following the member's declarator-id, and name lookup ([basic.lookup.unqual]) finds that the unqualified-id refers to a static member, enumerator, or nested type of the member's class (or of a base class of the member's class), the unqualified-id is transformed into a qualified-id expression in which the nested-name-specifier names the class scope from which the member is referenced. [ Note: See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions. — end note ]
It says the unqualified-id is transformed into a qualified-id expression in your situation.
int A::b = a;
You can set qualified-id but has no nested-name-specifier like this.
int A::b = ::a;
Because the name look up resolves the a as A::a. If you want to do this you will need to resolve the scope manually:
int A::b = ::a;
// ^ Global scope resolution
Live Example

[[maybe_unused]] applied to static data members

The draft standard states about [[maybe_unused]] in 10.6.6 item 2
"The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, an enumeration, or an enumerator."
Is there any reason to exclude static data members from this? i.e.
struct Foo {
[[maybe_unused]] static inline int foo = 0;
};
I ask as I have a static data member whose type has a non trivial constructor that does useful stuff but is otherwise unused.
[basic]/6 says that any object declaration constitutes a variable. “non-static data member” appears in the list alongside “variable” because a non-static data member of reference type is not a variable.

What is the differens between <class> tmp = <value>; and <class> tmp; tmp = <value>;? [duplicate]

After reading the question, I know the differences between declaration and definition. So does it mean definition equals declaration plus initialization?
Declaration
Declaration, generally, refers to the introduction of a new name in the program. For example, you can declare a new function by describing it's "signature":
void xyz();
or declare an incomplete type:
class klass;
struct ztruct;
and last but not least, to declare an object:
int x;
It is described, in the C++ standard, at §3.1/1 as:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
Definition
A definition is a definition of a previously declared name (or it can be both definition and declaration). For example:
int x;
void xyz() {...}
class klass {...};
struct ztruct {...};
enum { x, y, z };
Specifically the C++ standard defines it, at §3.1/1, as:
A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function- body, it declares a static data member in a class definition (9.2, 9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), it is a template-parameter (14.1), it is a parameter-declaration (8.3.5) in a function declarator that is not the declarator of a function-definition, or it is a typedef declaration (7.1.3), an alias-declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute- declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).
Initialization
Initialization refers to the "assignment" of a value, at construction time. For a generic object of type T, it's often in the form:
T x = i;
but in C++ it can be:
T x(i);
or even:
T x {i};
with C++11.
Conclusion
So does it mean definition equals declaration plus initialization?
It depends. On what you are talking about. If you are talking about an object, for example:
int x;
This is a definition without initialization. The following, instead, is a definition with initialization:
int x = 0;
In certain context, it doesn't make sense to talk about "initialization", "definition" and "declaration". If you are talking about a function, for example, initialization does not mean much.
So, the answer is no: definition does not automatically mean declaration plus initialization.
Declaration says "this thing exists somewhere":
int foo(); // function
extern int bar; // variable
struct T
{
static int baz; // static member variable
};
Definition says "this thing exists here; make memory for it":
int foo() {} // function
int bar; // variable
int T::baz; // static member variable
Initialisation is optional at the point of definition for objects, and says "here is the initial value for this thing":
int bar = 0; // variable
int T::baz = 42; // static member variable
Sometimes it's possible at the point of declaration instead:
struct T
{
static int baz = 42;
};
…but that's getting into more complex features.
For C, at least, per C11 6.7.5:
A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant, is the (only) declaration of the identifier;
for a typedef name, is the first (or only) declaration of the identifier.
Per C11 6.7.9.8-10:
An initializer specifies the initial value stored in an object ... if
an object that has automatic storage is not initialized explicitly,
its value is indeterminate.
So, broadly speaking, a declaration introduces an identifier and provides information about it. For a variable, a definition is a declaration which allocates storage for that variable.
Initialization is the specification of the initial value to be stored in an object, which is not necessarily the same as the first time you explicitly assign a value to it. A variable has a value when you define it, whether or not you explicitly give it a value. If you don't explicitly give it a value, and the variable has automatic storage, it will have an initial value, but that value will be indeterminate. If it has static storage, it will be initialized implicitly depending on the type (e.g. pointer types get initialized to null pointers, arithmetic types get initialized to zero, and so on).
So, if you define an automatic variable without specifying an initial value for it, such as:
int myfunc(void) {
int myvar;
...
You are defining it (and therefore also declaring it, since definitions are declarations), but not initializing it. Therefore, definition does not equal declaration plus initialization.
"So does it mean definition equals declaration plus initialization."
Not necessarily, your declaration might be without any variable being initialized like:
void helloWorld(); //declaration or Prototype.
void helloWorld()
{
std::cout << "Hello World\n";
}

What distinguishes the declaration, the definition and the initialization of a variable?

After reading the question, I know the differences between declaration and definition. So does it mean definition equals declaration plus initialization?
Declaration
Declaration, generally, refers to the introduction of a new name in the program. For example, you can declare a new function by describing it's "signature":
void xyz();
or declare an incomplete type:
class klass;
struct ztruct;
and last but not least, to declare an object:
int x;
It is described, in the C++ standard, at §3.1/1 as:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
Definition
A definition is a definition of a previously declared name (or it can be both definition and declaration). For example:
int x;
void xyz() {...}
class klass {...};
struct ztruct {...};
enum { x, y, z };
Specifically the C++ standard defines it, at §3.1/1, as:
A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function- body, it declares a static data member in a class definition (9.2, 9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), it is a template-parameter (14.1), it is a parameter-declaration (8.3.5) in a function declarator that is not the declarator of a function-definition, or it is a typedef declaration (7.1.3), an alias-declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute- declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).
Initialization
Initialization refers to the "assignment" of a value, at construction time. For a generic object of type T, it's often in the form:
T x = i;
but in C++ it can be:
T x(i);
or even:
T x {i};
with C++11.
Conclusion
So does it mean definition equals declaration plus initialization?
It depends. On what you are talking about. If you are talking about an object, for example:
int x;
This is a definition without initialization. The following, instead, is a definition with initialization:
int x = 0;
In certain context, it doesn't make sense to talk about "initialization", "definition" and "declaration". If you are talking about a function, for example, initialization does not mean much.
So, the answer is no: definition does not automatically mean declaration plus initialization.
Declaration says "this thing exists somewhere":
int foo(); // function
extern int bar; // variable
struct T
{
static int baz; // static member variable
};
Definition says "this thing exists here; make memory for it":
int foo() {} // function
int bar; // variable
int T::baz; // static member variable
Initialisation is optional at the point of definition for objects, and says "here is the initial value for this thing":
int bar = 0; // variable
int T::baz = 42; // static member variable
Sometimes it's possible at the point of declaration instead:
struct T
{
static int baz = 42;
};
…but that's getting into more complex features.
For C, at least, per C11 6.7.5:
A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant, is the (only) declaration of the identifier;
for a typedef name, is the first (or only) declaration of the identifier.
Per C11 6.7.9.8-10:
An initializer specifies the initial value stored in an object ... if
an object that has automatic storage is not initialized explicitly,
its value is indeterminate.
So, broadly speaking, a declaration introduces an identifier and provides information about it. For a variable, a definition is a declaration which allocates storage for that variable.
Initialization is the specification of the initial value to be stored in an object, which is not necessarily the same as the first time you explicitly assign a value to it. A variable has a value when you define it, whether or not you explicitly give it a value. If you don't explicitly give it a value, and the variable has automatic storage, it will have an initial value, but that value will be indeterminate. If it has static storage, it will be initialized implicitly depending on the type (e.g. pointer types get initialized to null pointers, arithmetic types get initialized to zero, and so on).
So, if you define an automatic variable without specifying an initial value for it, such as:
int myfunc(void) {
int myvar;
...
You are defining it (and therefore also declaring it, since definitions are declarations), but not initializing it. Therefore, definition does not equal declaration plus initialization.
"So does it mean definition equals declaration plus initialization."
Not necessarily, your declaration might be without any variable being initialized like:
void helloWorld(); //declaration or Prototype.
void helloWorld()
{
std::cout << "Hello World\n";
}