I just saw a question where a non static member of a class was initialized in the class definition. But if I try to compile the following code I get an error from the compiler.
class MyClass
{
int n = 2;
};
The error I'm getting is:
g++ -o ns nonstatic.cpp -Wall -Wextra -pedantic
nonstatic.cpp:3:13: error: ISO C++ forbids initialization of member ‘n’ [-fpermissive]
nonstatic.cpp:3:13: error: making ‘n’ static [-fpermissive]
nonstatic.cpp:3:13: error: ISO C++ forbids in-class initialization of non-const static member ‘n’
I always thought I must initialize such member in the constructor like this:
class MyClass
{
public:
MyClass ( void ) : n(2) {}
private:
int n;
};
Or with n initialized inside of the body of the constructor.
So my question is: when is one allowed to initialize a non static member outside the context of a class constructor?
kind regards,
when is one allowed to initialize a non static member of a class in C++?
One can do this already in C++11.
Just pass in -std=c++11 to the command line and you'll be able to.
Related
This question already has answers here:
Can typedef names be used to declare or define constructors?
(2 answers)
Closed 7 months ago.
This minimum reproducible piece of code
class MyClass
{
public:
explicit MyClass();
~MyClass();
};
using MyClassAlias = MyClass;
MyClassAlias::MyClassAlias()
{
}
MyClassAlias::~MyClassAlias()
{
}
int main()
{
MyClassAlias obj;
return 0;
}
gives the error:
a.cpp:11:1: error: ISO C++ forbids declaration of ‘MyClassAlias’ with no type [-fpermissive]
11 | MyClassAlias::MyClassAlias()
| ^~~~~~~~~~~~
a.cpp:11:1: error: no declaration matches ‘int MyClass::MyClassAlias()’
a.cpp:11:1: note: no functions named ‘int MyClass::MyClassAlias()’
a.cpp:1:7: note: ‘class MyClass’ defined here
1 | class MyClass
| ^~~~~~~
Only if I replace MyClassAlias::MyClassAlias() with MyClassAlias::MyClass(), it gets cured. At the same time, as you can see, it is okay to have MyClassAlias::~MyClassAlias() (the compiler gives no error).
Is there any way to fix this: to have consistency in naming?
The "names" (although these are not names in the technical sense of the standard) of the constructor and destructor are MyClass and ~MyClass respectively. They are based on the injected class name. You need to use these two to define them or write any declaration for them. You cannot use an alias name for these.
The same does not apply to the class name before the ::. It can be the name of an alias.
It seems that GCC accepts the alias as well for the destructor definition, but as far as I can tell that is not standard-conforming.
This question already has answers here:
Nonstatic member as a default argument of a nonstatic member function [duplicate]
(9 answers)
Closed 1 year ago.
Chapter 7.6 of the book C++ Primer says the following:
A nonstatic data member may not be used as a default argument because its value is part of the object of which it is a member. Using a nonstatic data member as a default argument provides no object from which to obtain the member’s value and so is an error.
Member functions can access class members, so why is it a problem when a default argument is used by a member function?
The short answer is: There is no a priori reason why it wouldn't be possible, but in C++ there is no mechanism to do it (at least not directly).
Default arguments are substituted at the call site. For example
void foo(int x = 42);
Then
foo();
is actually
foo(42);
With non-static members this doesn't work:
struct bar {
int y;
void moo(int x = y);
};
bar b;
b.moo(); // -> b.moo(y) ?!?
The default argument is replaced at the call site and this is not necessarily in the scope of the class. Outside of the scope of the class you need an instance to access a member.
Surely there could be rules to make it work, but instead C++ just says you cannot do it. However, you don't need it because there is a straightforward workaround:
struct bar {
int y;
void moo(int x);
void moo() { moo(y); }
};
This question already has an answer here:
Why class data members can't be initialized by direct initialization syntax?
(1 answer)
Closed 2 years ago.
Given this test fragment:
class Member
{
};
class MemberNoDefault
{
public:
MemberNoDefault(int x) {}
};
class Owner
{
inline static Member member1;
inline static Member member2();
inline static MemberNoDefault member3(10);
static MemberNoDefault member4;
};
MemberNoDefault Owner::member4(10);
This fails when compiling with GCC 9.3 on the line with member3 where it attempts to use a constructor with an argument. The errors are:
error: expected identifier before numeric constant
error: expected ',' or '...' before numeric constant
Shouldn't this work? This compiles successfully if I comment out the line with member3.
No, that is not a valid way to initialise a member inside the class definition.
You have to use brace-initialisation, or (where valid), an =:
inline static MemberNoDefault member3a{10};
inline static MemberNoDefault member3b = 10;
In this example, aggregate initialisation will work for you too:
inline static MemberNoDefault member3c = {10};
This is because the parentheses version of initialisation can be too easily confused with a function declaration (like how your member2 is actually a function), and they didn't want to make that mistake again. Although, personally, I think adding this inconsistency just made it worse.
This question already has answers here:
Why is this constexpr static member function not seen as constexpr when called?
(2 answers)
Closed 5 years ago.
Consider this trivial test code:
class Test
{
public:
Test() {/* empty */}
private:
enum {BLAH = 42};
static constexpr int Magic() {return BLAH*4;}
float f[Magic()];
};
int main(int argc, char ** argv)
{
Test t;
return 0;
}
When I try to compile it (under MacOS/X using clang++ from the latest XCode), I get this compiler error:
Jeremys-Mac-Pro:~ jaf$ clang++ -std=c++11 ./test.cpp
./test.cpp:11:14: error: fields must have a constant size: 'variable length
array in structure' extension will never be supported
float f[Magic()];
Can anyone explain why this is an error? For comparison, if I move the Magic() method out of the Test class and make it a free-standing function, it compiles as expected, but I don't really want to do that because I want to keep Magic() and BLAH private to the Test class if possible.
(Note: I'm not trying to use variable-length arrays here; rather I'm trying to declare an array whose size is determined by the computation of a function at compile-time)
It's because functions within a class aren't processed until the class is complete. This rule allows a function defined within a class to access members of that class that are defined later in the class than that function. As a result, Magic() does not yet have a definition, so can't be evaluated at that moment of compile time.
This is correct behavior, though the error the various compilers generate are not helpful for understanding the problem.
The formal rules are in the C++ standard at [class.member]/6:
A class is considered a completely-defined object type (6.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, noexcept-specifiers, and default member initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Member fields, order of construction
If i have a class with two members like this:
class A
{
int a;
int b;
A() {}
};
Is the order in which a and b are constructed undefined?
If I use cl, then no matter in which order I call the constructors, the members are always constructed in the order in which they are declared in the class. In this case it would always be a then b, even if I define the constructor for A like:
A() : b(), a() {}
But I am assuming that that is just the behaviour of the specific compiler.
No. Members are constructed in the order in which they are declared.
You are advised to arrange your initializer list in the same order, but you are not required to do so. It's just very confusing if you don't and may lead to hard-to-detect errors.
Example:
struct Foo {
int a; int b;
Foo() : b(4), a(b) { } // does not do what you think!
};
This construction is actually undefined behaviour, because you're reading an uninitialized variable in the initializer a(b).
Standard reference (C++11, 12.6.2/10):
— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
The order of initialization is the same as the order of declaration in the class.
If the order on the constructor's initialization list is different then compilers usually issue a warning. For example for the class:
class A {
public:
A() : b(1), a(b) {}
private
int a;
int b;
};
GCC will warn that:
$ g++ -Wall c.cc
c.cc:5: error: expected `:' before ‘int’
c.cc: In constructor ‘A::A()’:
c.cc:6: warning: ‘A::b’ will be initialized after
c.cc:5: warning: ‘int A::a’
c.cc:3: warning: when initialized here
This is because it can easily lead to errors. In the above example value of a will be unspecified.