MSVC const enum type - c++

const enum Alpha{
X=9,
Y=5,
Z=2
}p;
int main(){
enum Alpha a,b;
a= X;
b= Z;
p = X;
p = Y;
printf("%d",a+b-p);
return 0;
}
Why is p = X and p = Y allowed in MSVC compiler? This code outputs 6. Shouldn't a const value be assigned at initialization and never again?

That is a bug in the compiler itself. End of the story.
In fact, your little code shows two bugs in the compiler. The first bug is here itself:
const enum Alpha{
X=9,
Y=5,
Z=2
}p; //declaration of p is ill-formed!
The declaration of p is ill-formed, and thus the compiler should reject this code, because p is declared const but left uninitialized. A const scalar (and pod) type must be initialized in order to be well-formed:
const Alpha q; //ill-formed (same case is with p in your code)
const Alpha r = X; //well-formed
For detailed and extensive explanation, see this:
Why do const variables have to be initialized right away?

Looks like a bug, indeed.
First of all, global const objects must be initialized when defined, and default-initialization is not an option for enumeration types. According to Paragraph 8.5/6 of the C++11 Standard:
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
Secondly, a const object cannot be assigned after initialization.

Edited to match consensus that this is a compiler bug.
This works because the compiler erroneously thinks that p is of type Alpha and not const Alpha. If you rewrite this as
enum Alpha{....
} const p;
the compiler will correctly complain that a constant is not being initialized.
error C2734: 'p' : const object must be initialized if not extern
error C3892: 'p' : you cannot assign to a variable that is const
If you assign the constant,
enum Alpha{....
} const p = Y;
and remove the assignment to p, everything compiles and works as expected.

Related

C++ : Default constructor for struct doesn't work? [duplicate]

The C++ standard (section 8.5) says:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
Why? I can't think of any reason why a user-provided constructor is required in this case.
struct B{
B():x(42){}
int doSomeStuff() const{return x;}
int x;
};
struct A{
A(){}//other than "because the standard says so", why is this line required?
B b;//not required for this example, just to illustrate
//how this situation isn't totally useless
};
int main(){
const A a;
}
The reason is that if the class doesn't have a user-defined constructor, then it can be POD, and the POD class is not initialized by default. So if you declare a const object of POD which is uninitialized, what use of it? So I think the Standard enforces this rule so that the object can actually be useful.
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
const POD p3 = POD(); //initialized
const POD p4; //uninitialized - error - as we cannot change it later on!
But if you make the class a non-POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Note the difference between POD and non-POD.
User-defined constructor is one way to make the class non-POD. There are several ways you can do that.
struct nonPOD_B
{
virtual void f() {} //virtual function make it non-POD
};
nonPOD_B b1; //initialized
const nonPOD_B b2; //initialized
Notice nonPOD_B doesn't defined user-defined constructor. Compile it. It will compile:
http://www.ideone.com/h7TsA
And comment the virtual function, then it gives error, as expected:
http://www.ideone.com/SWk7B
Well, I think, you misunderstood the passage. It first says this (§8.5/9):
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; [...]
It talks about non-POD class possibly cv-qualified type. That is, the non-POD object shall be default-initialized if there is no initializer specified. And what is default-initialized? For non-POD, the spec says (§8.5/5),
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
It simply talks about default constructor of T, whether its user-defined or compiler-generated is irrelevant.
If you're clear up to this, then understand what the spec next says ((§8.5/9),
[...]; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor.
So this text implies, the program will be ill-formed if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
By the way, this compiles fine, because its non-POD, and can be default-initialized.
Pure speculation on my part, but consider that other types have a similar restriction, too:
int main()
{
const int i; // invalid
}
So not only is this rule consistent, but it also (recursively) prevents unitialized const (sub)objects:
struct X {
int j;
};
struct A {
int i;
X x;
}
int main()
{
const A a; // a.i and a.x.j in unitialized states!
}
As for the other side of the question (allowing it for types with a default constructor), I think the idea is that a type with a user-provided default constructor is supposed to always be in some sensible state after construction. Note that the rules as they are allow for the following:
struct A {
explicit
A(int i): initialized(true), i(i) {} // valued constructor
A(): initialized(false) {}
bool initialized;
int i;
};
const A a; // class invariant set up for the object
// yet we didn't pay the cost of initializing a.i
Then perhaps we could formulate a rule like 'at least one member must be sensibly initialized in a user-provided default constructor', but that's way too much time spent trying to protect against Murphy. C++ tends to trust the programmer on certain points.
This was considered a defect (against all versions of the standard) and it was resolved by Core Working Group (CWG) Defect 253. The new wording for the standard states in http://eel.is/c++draft/dcl.init#7
A class type T is const-default-constructible if
default-initialization of T would invoke a user-provided constructor
of T (not inherited from a base class) or if
each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X
is const-default-constructible,
if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
if T is not a union, for each anonymous union member with at least one non-static data member (if any), exactly one non-static data
member has a default member initializer, and
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a
const-qualified type T, T shall be a const-default-constructible class
type or array thereof.
This wording essentially means that the obvious code works. If you initialize all of your bases and members, you can say A const a; regardless of how or if you spell any constructors.
struct A {
};
A const a;
gcc has accepted this since 4.6.4. clang has accepted this since 3.9.0. Visual Studio also accepts this (at least in 2017, not sure if sooner).
I was watching Timur Doumler's talk at Meeting C++ 2018 and I finally realised why the standard requires a user-provided constructor here, not merely a user-declared one. It has to do with the rules for value initialisation.
Consider two classes: A has a user-declared constructor, B has a user-provided constructor:
struct A {
int x;
A() = default;
};
struct B {
int x;
B() {}
};
At first glance, you might think these two constructors will behave the same. But see how value initialisation behaves differently, while only default initialisation behaves the same:
A a; is default initialisation: the member int x is uninitialised.
B b; is default initialisation: the member int x is uninitialised.
A a{}; is value initialisation: the member int x is zero-initialised.
B b{}; is value initialisation: the member int x is uninitialised.
Now see what happens when we add const:
const A a; is default initialisation: this is ill-formed due to the rule quoted in the question.
const B b; is default initialisation: the member int x is uninitialised.
const A a{}; is value initialisation: the member int x is zero-initialised.
const B b{}; is value initialisation: the member int x is uninitialised.
An uninitialised const scalar (e.g. the int x member) would be useless: writing to it is ill-formed (because it's const) and reading from it is UB (because it holds an indeterminate value). So this rule prevents you from creating such a thing, by forcing you to either add an initialiser or opt-in to the dangerous behaviour by adding a user-provided constructor.
I think it would be nice to have an attribute like [[uninitialized]] to tell the compiler when you're intentionally not initialising an object. Then we wouldn't be forced to make our class not trivially default constructible to get around this corner case. This attribute has actually been proposed, but just like all the other standard attributes, it does not mandate any normative behaviour, being merely a hint to the compiler.
Congratulations, you've invented a case in which there need not be any user defined constructor for the const declaration with no initializer to make sense.
Now can you come up with a reasonable re-wording of the rule that covers your case but still makes the cases that should be illegal illegal? Is it less than 5 or 6 paragraphs? Is it easy and obvious how it should be applied in any situation?
I posit that coming up with a rule that allows the declaration you created to make sense is really hard, and making sure that the rule can be applied in a way that makes sense to people when reading code is even harder. I would prefer a somewhat restrictive rule that was the right thing to do in most cases to a very nuanced and complex rule that was difficult to understand and apply.
The question is, is there a compelling reason the rule should be more complex? Is there some code that would otherwise be very difficult to write or understand that can be written much more simply if the rule is more complex?

C++: function call expression with braced-init-list - does standard prescribe to ignore braces in a trivial case of a single element list?

Consider the following example:
class X;
void f(const X &);
void g()
{
X x;
f({x});
}
Does standard require that an implementation ignored curly braces in that case? Without any optimization involved. If yes, than since which version?
On a first glance, it looks like by rules there should be a temporary created - completely unnecessary, of course, but still. Looking at list initialization I cannot find anything relevant. X is not an aggregate here.
Both GCC and Clang, even with -O0, produce code without temporary created - even if an X copy constructor has observable side-effects and even if X has X(std::initializer_list<X>) constructor.
The initialization of X const &x (the argument of f) in f({x}) is list initialization in a copy initialization context, by [dcl.init]/15. Thus, we can drop the function and just ask what this means:
int main() {
X x;
X const &y = {x}; // still copy list initialization
}
Now, the first clause in [dcl.init.list] to apply to this is [dcl.init.list]/3.9, which states that you basically just drop the braces.
... if the initializer list has a single element of type E and either T [here X const&] is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); ....
X const& is in fact a reference type, but its referenced type X const is indeed related to the initializer's type, X, so the clause still applies. Now we just have
int main() {
X x;
X const &y = x; // (non-list/"plain") copy-initialization
}
and of course that doesn't call X's constructor (by [dcl.init.ref]/5.1).
Note that the above quote appears slightly reworded on your cppreference page, too:
... (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type whose referenced type is same as or is a base class of the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), ....
Perhaps the "T isn't a reference type" or "T is not a class type" made this fly under the radar, but this is the clause you were looking for, since a) a reference type is indeed not a class type and b) the "or ..." in the preconditions makes it apply. Judging by the lack of versioning boxes, this behavior would be as old as list initialization itself: since C++11.

Is pointer type a literal type?

A scalar type is defined as
Trait class that identifies whether T is a scalar type. A scalar type
is a type that has built-in functionality for the addition operator
without overloads (arithmetic, pointer, member pointer, enum and
std::nullptr_t).
It inherits from integral_constant as being either true_type or
false_type, depending on whether T is a scalar type, no matter its
const and/or volative qualification.
It means pointer is scalar type.
Now if we go to definition of literal type:
A type is a literal type if it is:
a scalar type; or
a reference type; or
an array of literal type; or
-a class type (Clause 9) that has all of the following properties:
it has a trivial destructor,
every constructor call and full-expression in the brace-or-equal-initializers for non-static data members (if any) is a constant expression (5.19),
it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
all of its non-static data members and base classes are of literal types.
Now, combining above 2 statements, it means pointer is literal type. However pointer can not be constexpr. can someone please clarify?
further see following code:
int a = 7;
constexpr int *pointer1 = &a;
int main ()
{
int b = 4;
constexpr int *pointer2 = &b;
}
pointer1 is fine but pointer 2 gives error. does that mean pointer to global is fine but to automatic variable is not? Does standard mention this anywhere ?
Pointers are literal types. They can be constexpr under certain conditions:
[expr.const] 6
... [a pointer is constexpr if] it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.
(Where "object with static storage duration" means a global or static object, or a subobject of such object.)
A demo:
int x;
int main()
{
constexpr int *ptr = &x; // Compiles.
// Doesn't compile: `error: '& foo' is not a constant expression`
// int foo;
// constexpr int *bar = &foo;
}
Apparently GCC (with -pedantic-errors -std=c++11/14/17) happily accepts out-of-range constexpr pointer arithmetic: constexpr int *ptr = &x - 10;, which seems like a bug to me.
Yes they are literals; yes they can be constexpr. To demonstrate:
constexpr int* foo=0;
int x = 7;
constexpr int* ptr=&x;
int main(){}

Why does C++ require a user-provided default constructor to default-construct a const object?

The C++ standard (section 8.5) says:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
Why? I can't think of any reason why a user-provided constructor is required in this case.
struct B{
B():x(42){}
int doSomeStuff() const{return x;}
int x;
};
struct A{
A(){}//other than "because the standard says so", why is this line required?
B b;//not required for this example, just to illustrate
//how this situation isn't totally useless
};
int main(){
const A a;
}
The reason is that if the class doesn't have a user-defined constructor, then it can be POD, and the POD class is not initialized by default. So if you declare a const object of POD which is uninitialized, what use of it? So I think the Standard enforces this rule so that the object can actually be useful.
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
const POD p3 = POD(); //initialized
const POD p4; //uninitialized - error - as we cannot change it later on!
But if you make the class a non-POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Note the difference between POD and non-POD.
User-defined constructor is one way to make the class non-POD. There are several ways you can do that.
struct nonPOD_B
{
virtual void f() {} //virtual function make it non-POD
};
nonPOD_B b1; //initialized
const nonPOD_B b2; //initialized
Notice nonPOD_B doesn't defined user-defined constructor. Compile it. It will compile:
http://www.ideone.com/h7TsA
And comment the virtual function, then it gives error, as expected:
http://www.ideone.com/SWk7B
Well, I think, you misunderstood the passage. It first says this (§8.5/9):
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; [...]
It talks about non-POD class possibly cv-qualified type. That is, the non-POD object shall be default-initialized if there is no initializer specified. And what is default-initialized? For non-POD, the spec says (§8.5/5),
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
It simply talks about default constructor of T, whether its user-defined or compiler-generated is irrelevant.
If you're clear up to this, then understand what the spec next says ((§8.5/9),
[...]; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor.
So this text implies, the program will be ill-formed if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
By the way, this compiles fine, because its non-POD, and can be default-initialized.
Pure speculation on my part, but consider that other types have a similar restriction, too:
int main()
{
const int i; // invalid
}
So not only is this rule consistent, but it also (recursively) prevents unitialized const (sub)objects:
struct X {
int j;
};
struct A {
int i;
X x;
}
int main()
{
const A a; // a.i and a.x.j in unitialized states!
}
As for the other side of the question (allowing it for types with a default constructor), I think the idea is that a type with a user-provided default constructor is supposed to always be in some sensible state after construction. Note that the rules as they are allow for the following:
struct A {
explicit
A(int i): initialized(true), i(i) {} // valued constructor
A(): initialized(false) {}
bool initialized;
int i;
};
const A a; // class invariant set up for the object
// yet we didn't pay the cost of initializing a.i
Then perhaps we could formulate a rule like 'at least one member must be sensibly initialized in a user-provided default constructor', but that's way too much time spent trying to protect against Murphy. C++ tends to trust the programmer on certain points.
This was considered a defect (against all versions of the standard) and it was resolved by Core Working Group (CWG) Defect 253. The new wording for the standard states in http://eel.is/c++draft/dcl.init#7
A class type T is const-default-constructible if
default-initialization of T would invoke a user-provided constructor
of T (not inherited from a base class) or if
each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X
is const-default-constructible,
if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
if T is not a union, for each anonymous union member with at least one non-static data member (if any), exactly one non-static data
member has a default member initializer, and
each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a
const-qualified type T, T shall be a const-default-constructible class
type or array thereof.
This wording essentially means that the obvious code works. If you initialize all of your bases and members, you can say A const a; regardless of how or if you spell any constructors.
struct A {
};
A const a;
gcc has accepted this since 4.6.4. clang has accepted this since 3.9.0. Visual Studio also accepts this (at least in 2017, not sure if sooner).
I was watching Timur Doumler's talk at Meeting C++ 2018 and I finally realised why the standard requires a user-provided constructor here, not merely a user-declared one. It has to do with the rules for value initialisation.
Consider two classes: A has a user-declared constructor, B has a user-provided constructor:
struct A {
int x;
A() = default;
};
struct B {
int x;
B() {}
};
At first glance, you might think these two constructors will behave the same. But see how value initialisation behaves differently, while only default initialisation behaves the same:
A a; is default initialisation: the member int x is uninitialised.
B b; is default initialisation: the member int x is uninitialised.
A a{}; is value initialisation: the member int x is zero-initialised.
B b{}; is value initialisation: the member int x is uninitialised.
Now see what happens when we add const:
const A a; is default initialisation: this is ill-formed due to the rule quoted in the question.
const B b; is default initialisation: the member int x is uninitialised.
const A a{}; is value initialisation: the member int x is zero-initialised.
const B b{}; is value initialisation: the member int x is uninitialised.
An uninitialised const scalar (e.g. the int x member) would be useless: writing to it is ill-formed (because it's const) and reading from it is UB (because it holds an indeterminate value). So this rule prevents you from creating such a thing, by forcing you to either add an initialiser or opt-in to the dangerous behaviour by adding a user-provided constructor.
I think it would be nice to have an attribute like [[uninitialized]] to tell the compiler when you're intentionally not initialising an object. Then we wouldn't be forced to make our class not trivially default constructible to get around this corner case. This attribute has actually been proposed, but just like all the other standard attributes, it does not mandate any normative behaviour, being merely a hint to the compiler.
Congratulations, you've invented a case in which there need not be any user defined constructor for the const declaration with no initializer to make sense.
Now can you come up with a reasonable re-wording of the rule that covers your case but still makes the cases that should be illegal illegal? Is it less than 5 or 6 paragraphs? Is it easy and obvious how it should be applied in any situation?
I posit that coming up with a rule that allows the declaration you created to make sense is really hard, and making sure that the rule can be applied in a way that makes sense to people when reading code is even harder. I would prefer a somewhat restrictive rule that was the right thing to do in most cases to a very nuanced and complex rule that was difficult to understand and apply.
The question is, is there a compelling reason the rule should be more complex? Is there some code that would otherwise be very difficult to write or understand that can be written much more simply if the rule is more complex?

Standard reference for int foo = foo

int foo = foo; compiles.
Which part of the C++ standard allows this?
3.3.1 Point of declaration [basic.scope.pdecl]
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any),
The behaviour is well defined if the declaration is at file scope. If you have the declaration at function scope and if you use foo later on [which would be initialized to some unspecified value in that case] the behaviour would be undefined.
This?
int main() {
int foo = foo;
}
The object foo does exist after the =, according to [basic.scope.pdecl]:
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any).
However, the program as a whole is undefined, because you use (on the RHS) an uninitialised value:
int x = x;
Here [..] x is initialized with its own (indeterminate) value.
And:
Though "inferred and ill-specified" by the standard, an lvalue-to-rvalue conversion is performed on the RHS expression foo.
And ([conv.lval]):
An lvalue (3.10) of a non-function,
non-array type T can be converted to
an rvalue. If T is an incomplete type,
a program that necessitates this
conversion is ill-formed. If the
object to which the lvalue refers is
not an object of type T and is not an
object of a type derived from T, or if
the object is uninitialized, a program
that necessitates this conversion has
undefined behavior.
With proper warning levels, you will get told about it; however, programs invoking Undefined Behaviour are allowed to compile. They just can do anything at all when you run them.
Or, what about this?
int foo = foo;
int main() {}
Notice that foo is a "global". These are zero-initialised as a first step, according to [basic.start.init]:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
So you'll get an int foo with value 0; it's valid, at this point, as per [basic.scope.pdecl] above, and as per [stmt.decl]:
The zero-initialization (8.5) of all
local objects with static storage
duration (3.7.1) is performed before
any other initialization takes place. [..]
You then value-initialise it to foo (itself), i.e. 0.
This is well-defined... if a little cryptic.
In the interests of thoroughness, here's a third and final case:
int foo = 42;
int main() {
int foo = foo;
}
Sadly, this is the same as the first case. Since the local foo is already declared and in scope by the time the initializer is evaluated, the initializer uses the local foo and you're still stuck with the Undefined Behaviour. The global foo is not used.