There is this code:
namespace N {
struct B {
void f() {
i;
j;
}
int i;
};
int j;
}
int main() {
return 0;
}
Variable i is found but variable j is not. How does it work that variable in the class can be used before it is declared but the same does not work for namespace? How i is found - compiler parses first all class to find all members then bind it with references from member functions?
Indeed, the bodies of member functions (as well as variable initializers) are processed in a later phase than the class definition. You can check for yourself that the "declare before use" rule is still in full effect for class members, by trying to use members in other member declarations:
struct B
{
char c[sizeof i];
int i;
};
Demonstration: http://ideone.com/v1ksio
struct B2
{
decltype(i) f();
int i;
};
This also affects usage of the class itself which requires a complete type.
struct B
{
static char c[sizeof (B)];
};
Demonstration: http://ideone.com/Z9XOzm
But this is ok, because variable initializers are processed when the construction definitions are, where all members are known and the type is complete:
struct B
{
unsigned r{sizeof s};
unsigned s{sizeof (B)};
};
Related
AFAIK, data member of enclosing class are also visible in nested class.
struct A {
struct B {
int arr[n]; // how come n is not visible here, but it is visible in next statement.
int x = n;
};
static const int n = 5;
};
see live demo here
how come n is not visible here, but it is visible in next statement.
Because int x = n; is a complete class context while int arr[n]; is not. This can be understood from class.mem which states:
6) A complete-class context of a class is a:
6.4) default member initializer
within the member-specification of the class.
[ Note: A complete-class context of a nested class is also a complete-class context of any enclosing class, if the nested class is defined within the member-specification of the enclosing class.
— end note
]
7) A class is considered a completely-defined object type ([basic.types]) (or complete type) at the closing } of the class-specifier. The class is regarded as complete within its complete-class contexts; otherwise it is regarded as incomplete within its own class member-specification.
(emphasis mine)
Note that the n inside int arr[n]; is part of the type of the array but the above quoted statement doesn't allow n to be used as part of a type of a non-static data member and hence the error. For the same reason, we will get the same error if we wrote:
struct A {
struct B {
int x = n;
//----------------------v--------->same error as before
std::array<int, n> arr;
};
static constexpr int n = 5;
};
My answer is more like intuition of why this is so:
In int arr[n] n is used in definition of a filed, while in int x = n n is used to initialize a field. It is like B() : x(n) {}.
Think of the following example:
struct A {
struct B {
int arr[n];
int x = n;
};
static constexpr int n = offsetof(B, x);
};
Here the value of n is dependent on the size of arr and size of the arr is dependent on n. It is a cross dependency. Therefore the struct is not well defined.
If the rules of the C++ was so that your use case be legal, then this should also be legal, which can't be. However, it still allow us to use offsetof in initialization, because why not?
Something about evaluation variable in left-hand side of assignment, not a computer language expert, the following worked.
#include <iostream>
using namespace std;
struct A {
struct B {
int *arr = new int[n]();
int x = n;
};
static const int n = 5;
};
int main() {
cout << "Hello World!";
return 0;
}
#include <iostream>
using namespace std;
class T1
{
const int t = 100;
public:
T1()
{
cout << "T1 constructor: " << t << endl;
}
};
When I am trying to initialize the const member variable t with 100. But it's giving me the following error:
test.cpp:21: error: ISO C++ forbids initialization of member ‘t’
test.cpp:21: error: making ‘t’ static
How can I initialize a const value?
The const variable specifies whether a variable is modifiable or not. The constant value assigned will be used each time the variable is referenced. The value assigned cannot be modified during program execution.
Bjarne Stroustrup's explanation sums it up briefly:
A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
A const variable has to be declared within the class, but it cannot be defined in it. We need to define the const variable outside the class.
T1() : t( 100 ){}
Here the assignment t = 100 happens in initializer list, much before the class initilization occurs.
Well, you could make it static:
static const int t = 100;
or you could use a member initializer:
T1() : t(100)
{
// Other constructor stuff here
}
There are couple of ways to initialize the const members inside the class..
Definition of const member in general, needs initialization of the variable too..
1) Inside the class , if you want to initialize the const the syntax is like this
static const int a = 10; //at declaration
2) Second way can be
class A
{
static const int a; //declaration
};
const int A::a = 10; //defining the static member outside the class
3) Well if you don't want to initialize at declaration, then the other way is to through constructor, the variable needs to be initialized in the initialization list(not in the body of the constructor). It has to be like this
class A
{
const int b;
A(int c) : b(c) {} //const member initialized in initialization list
};
If you don't want to make the const data member in class static, You can initialize the const data member using the constructor of the class.
For example:
class Example{
const int x;
public:
Example(int n);
};
Example::Example(int n):x(n){
}
if there are multiple const data members in class you can use the following syntax to initialize the members:
Example::Example(int n, int z):x(n),someOtherConstVariable(z){}
You can upgrade your compiler to support C++11 and your code would work perfectly.
Use initialization list in constructor.
T1() : t( 100 )
{
}
Another solution is
class T1
{
enum
{
t = 100
};
public:
T1();
};
So t is initialised to 100 and it cannot be changed and it is private.
If a member is a Array it will be a little bit complex than the normal is:
class C
{
static const int ARRAY[10];
public:
C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};
or
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
Another possible way are namespaces:
#include <iostream>
namespace mySpace {
static const int T = 100;
}
using namespace std;
class T1
{
public:
T1()
{
cout << "T1 constructor: " << mySpace::T << endl;
}
};
The disadvantage is that other classes can also use the constants if they include the header file.
This is the right way to do. You can try this code.
#include <iostream>
using namespace std;
class T1 {
const int t;
public:
T1():t(100) {
cout << "T1 constructor: " << t << endl;
}
};
int main() {
T1 obj;
return 0;
}
if you are using C++10 Compiler or below then you can not initialize the cons member at the time of declaration. So here it is must to make constructor to initialise the const data member. It is also must to use initialiser list T1():t(100) to get memory at instant.
you can add static to make possible the initialization of this class member variable.
static const int i = 100;
However, this is not always a good practice to use inside class declaration, because all objects instacied from that class will shares the same static variable which is stored in internal memory outside of the scope memory of instantiated objects.
In C++ you cannot initialize any variables directly while the declaration.
For this we've to use the concept of constructors.
See this example:-
#include <iostream>
using namespace std;
class A
{
public:
const int x;
A():x(0) //initializing the value of x to 0
{
//constructor
}
};
int main()
{
A a; //creating object
cout << "Value of x:- " <<a.x<<endl;
return 0;
}
Hope it would help you!
I want to define an aggregate with a number of mutable fields (to save it in std::set or std::priority_queue and modify it in future, surely saving the container invariants). I tried the following syntax and it was compiled successfully:
#include <cstdlib>
int
main()
{
struct X
{
mutable struct
{
int i;
int j;
};
};
X const x{};
//x.i = 1;
return EXIT_SUCCESS;
}
Live example for clang 3.8.
But statement x.i = 1; gives an error:
error: cannot assign to variable 'x' with const-qualified type 'const X'
My intention was to group a plenty of sequential fileds and apply mutable keyword to the group.
Is this syntax wrong? If so, what is an intention of compiler makers to allow such a syntax if any?
ADDITIONAL:
Code:
#include <cstdlib>
int
main()
{
struct X
{
mutable struct
{
int i;
int j;
};
void f() const { i = 1; }
};
X const x{};
//x.i = 1;
x.f();
return EXIT_SUCCESS;
}
gives an error too:
error: cannot assign to non-static data member within const member function 'f'
note: member function 'main()::X::f' is declared const here
void f() const { i = 1; }
The trouble comes from the mix between the non-standard (in C++) usage of anonymous struct together with the mutable. The latter is a storage class specifier that is meant to be used for members and not for types.
Alternative 1: define an intermediate member for your anonymous struct:
You can define a member that will then be mutable, according to the rules of standard C++:
struct X
{
mutable struct
{
int i;
int j;
} y;
};
X const x{};
x.y.i = 1;
Live demo
Alternative 2: make every members in the anonymous struct mutable:
You can otherwise define the members within the struct as being mutable. As the anonymous struct merges these members into the enclosing struct, the mutable property will be passed on:
struct X
{
struct
{
mutable int i;
mutable int j;
};
};
Online demo
What does the standard say ?
The standatad C++ doen't allow anonymous struct. Anonymous struct is a compiler extension for C11 compatibility.
The C++ standard allows however anonymous unions. But it sets restrictions, notably:
9.5/6: A storage class is not allowed in a declaration of an anonymous union in a class scope.
So when compiling the following code:
struct X
{
mutable union
{
int i;
int j;
};
};
the compiler shall and will issue a very specific error:
prog.cpp:11:13: error: a storage class on an anonymous aggregate in class scope is not allowed
mutable union
I think that it is not consistent to allow using a storage class specifier on an anonymous struct (and apparently ignoring it) and to issues an error for an anonymous union. According to me, this shall be reported as a compiler bug. In anycase, you should adopt alternative 1 (portable & compliant) or alternative 2 (compiler dependent, but more consistent with the standard).
#include <iostream>
using namespace std;
class T1
{
const int t = 100;
public:
T1()
{
cout << "T1 constructor: " << t << endl;
}
};
When I am trying to initialize the const member variable t with 100. But it's giving me the following error:
test.cpp:21: error: ISO C++ forbids initialization of member ‘t’
test.cpp:21: error: making ‘t’ static
How can I initialize a const value?
The const variable specifies whether a variable is modifiable or not. The constant value assigned will be used each time the variable is referenced. The value assigned cannot be modified during program execution.
Bjarne Stroustrup's explanation sums it up briefly:
A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
A const variable has to be declared within the class, but it cannot be defined in it. We need to define the const variable outside the class.
T1() : t( 100 ){}
Here the assignment t = 100 happens in initializer list, much before the class initilization occurs.
Well, you could make it static:
static const int t = 100;
or you could use a member initializer:
T1() : t(100)
{
// Other constructor stuff here
}
There are couple of ways to initialize the const members inside the class..
Definition of const member in general, needs initialization of the variable too..
1) Inside the class , if you want to initialize the const the syntax is like this
static const int a = 10; //at declaration
2) Second way can be
class A
{
static const int a; //declaration
};
const int A::a = 10; //defining the static member outside the class
3) Well if you don't want to initialize at declaration, then the other way is to through constructor, the variable needs to be initialized in the initialization list(not in the body of the constructor). It has to be like this
class A
{
const int b;
A(int c) : b(c) {} //const member initialized in initialization list
};
If you don't want to make the const data member in class static, You can initialize the const data member using the constructor of the class.
For example:
class Example{
const int x;
public:
Example(int n);
};
Example::Example(int n):x(n){
}
if there are multiple const data members in class you can use the following syntax to initialize the members:
Example::Example(int n, int z):x(n),someOtherConstVariable(z){}
You can upgrade your compiler to support C++11 and your code would work perfectly.
Use initialization list in constructor.
T1() : t( 100 )
{
}
Another solution is
class T1
{
enum
{
t = 100
};
public:
T1();
};
So t is initialised to 100 and it cannot be changed and it is private.
If a member is a Array it will be a little bit complex than the normal is:
class C
{
static const int ARRAY[10];
public:
C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};
or
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
Another possible way are namespaces:
#include <iostream>
namespace mySpace {
static const int T = 100;
}
using namespace std;
class T1
{
public:
T1()
{
cout << "T1 constructor: " << mySpace::T << endl;
}
};
The disadvantage is that other classes can also use the constants if they include the header file.
This is the right way to do. You can try this code.
#include <iostream>
using namespace std;
class T1 {
const int t;
public:
T1():t(100) {
cout << "T1 constructor: " << t << endl;
}
};
int main() {
T1 obj;
return 0;
}
if you are using C++10 Compiler or below then you can not initialize the cons member at the time of declaration. So here it is must to make constructor to initialise the const data member. It is also must to use initialiser list T1():t(100) to get memory at instant.
you can add static to make possible the initialization of this class member variable.
static const int i = 100;
However, this is not always a good practice to use inside class declaration, because all objects instacied from that class will shares the same static variable which is stored in internal memory outside of the scope memory of instantiated objects.
In C++ you cannot initialize any variables directly while the declaration.
For this we've to use the concept of constructors.
See this example:-
#include <iostream>
using namespace std;
class A
{
public:
const int x;
A():x(0) //initializing the value of x to 0
{
//constructor
}
};
int main()
{
A a; //creating object
cout << "Value of x:- " <<a.x<<endl;
return 0;
}
Hope it would help you!
Why should this be an error?
int a = 0;
a = 42;
int main()
{
}
A possibe match for this behavior i could find:
(3.4.1/4) A name used in global scope, outside of any function, class
or user-declared namespace, shall be declared before its use in global
scope.
Could this be a defect in standard?
int a = 0; //it is a declaration (and definition too) statement
a = 42; //it is an assignment statement
The second line is the cause of error, for it is an assignment statement.
At the namespace-level, only declaration and definition statements are allowed. Assignment-statements are not allowed at namespace level.
And by "shall be declared before its use in global scope" (from the spec's quotation) means the following:
int a = 42;
int b = 2 * a; //a is being used here
int c = a + b; //both a and b are being used here
If you define type instead, then:
struct A {}; //definition of A
struct B { A a; }; //a is declared as member of B
//(which means, A is being "used")
void f(const A&, const B&); //both A and B are used in the declaration of f
You cannot write an assignment statement like that in the global namespace
it needs to be either in main or in some [member] function
int main()
{
a=42;
return 0;
}