C++17 inline static member class variable error with GCC [duplicate] - c++

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.

Related

Why does constexpr attribute not work when applied to a static method? [duplicate]

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.

Why non-static data members of class cannot be given default values using '( )'? [duplicate]

This question already has an answer here:
Why can in-class initializers only use = or {}? [duplicate]
(1 answer)
Closed 5 years ago.
I'm just going through the basic OOP concepts in C++ and came across the following:
class A{
public:
int i(20); //line 1
};
int main()
{
int j(20);
cout<<j<<endl;
A obj;
cout<<obj.i<<endl;
}
I get the following error at line1 when compiling (tried in both gcc and MSVC++),
expected identifier before numeric constant
I know how to assign default value for a non-static member (which can be done from C++11 on wards in different ways), but I couldn't get the reason why only this kind of default value initialization is not possible as doing the same initialization (for normal variables) anywhere else is valid.
What could be the reason for such restriction?
Edited:
From the links and answer provided, it is because "it might read as function declaration in some cases. Because of this ambiguity, it is not allowed."
But consider the following case:
//global scope
struct B{
int j;
};
int B = 10;
int object(B);
This is also a similar case, where int object(B) might be understood as a function object taking B object as argument and with int return type.
I tried this in gcc and MSVC++ and object is treated as an int variable. Why it is not restricted in this case?
Using parentheses was deemed to be too confusing since it would read very similarly to a function declaration. Think about the case of a default constructor:
class A{
public:
int i(); // function declaration -- did you mean to
// use the default constructor instead?
};
There are other ways to do it though:
class A{
public:
int i = 20;
int i{20};
int i = {20};
};

Assign value to private static variable in a class [duplicate]

This question already has answers here:
Undefined reference to static class member
(9 answers)
How to initialize private static members in C++?
(18 answers)
Closed 6 years ago.
I have a file A.hpp as such:
class A
{
private:
static std::string s;
public:
void modify_string();
};
I am implementing this in a file A.cpp as such:
#include "A.hpp"
void A::modify_string()
{
s = "something"; // Error here.
}
My main class:
int main()
{
A a;
a.modify_string();
}
I understand static variables are shared by all the class instances. I also went through this SO post where it says how to access the static member. Public static member of class . Could you please let me know where my concept is missing at?
Edit:
I am getting this error:
error: undefined reference to A::s
When you define:
void modify_string() {
s = "something"; // Error here.
}
You are creating a new function, not defining the member function modify_string of the class A. You need to do:
void A::modify_string() {
To inform the compiler that you are defining the member function modify_string for class A.
You also need a ; after your class definition.
Finally, the variable s is static so it needs to be defined seperatly somewhere so the linker can find a reference to it. So add:
std::string A::s = "default";
This was clearly described in the link you provided for your question.
Here is a working example: http://ideone.com/iQ6Kux
You need to reserve storage for s in exactly one compilation unit.
Do that by writing
std::string A::s;
In exactly one source file.
Your definition void modify_string() {...} in A.cpp is not defining the member function of the class, it's defining a separate global function with the same name. You probably meant
void A::modify_string()
{
s = "something";
}

static member vs static const member instantiation - what's the difference? [duplicate]

This question already has answers here:
Why can't I initialize non-const static member or static array in class?
(5 answers)
Closed 7 years ago.
What exactly is the difference between these two members in question of initialization and instantiation?:
class Test {
// ctor, dtor, ... here
private:
static int m_test = 0; // error - non-const ...
static const int m_const_test = 0; // working - const ...
};
Why is initialization of non-const members not valid?
And when will both variables (assuming non-const member without init!) be instantiated?
Edit: Even if a good part of this question is superimposable to the mentioned posts, i don't think that every part of my question is answered in these entries.
BR, Tuna
If multiple compilation units include your class definition then in which one should be your static int m_test = 0 be placed? For const static ... it does not matter because it is const.
m_const_test being declared as const can´t be changed.
So, you can save a little bit of time using m_const_test, but is not as flexible as m_test.

Is initializing non static members allowed outside of a class constructor?

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.