union value {
int i;
bool j;
};
class Json {
public:
Json(int i): m_value.i(i) {};//error
m_value.i = i; //correct
private:
value m_value;
};
Can a union be initialized in initializer-list? If so, how? If not, why not?
If you have a compiler that conforms to the C++20 Standard (or later), then you can use a designated initializer in the "initializer list", to initialize (and, thus, activate) either member of your union, like so:
union value {
int i;
bool j;
};
class Json {
public:
Json(int iarg) : m_value{ .i = iarg } { }
Json(bool barg) : m_value{ .j = barg } { }
private:
value m_value;
};
However, before C++20, designated initializers were not part of C++ (though they have been part of C for some time); in such cases, you can only initialize the first member of the union:
union value {
int i;
bool j;
};
class Json {
public:
Json(int iarg) : m_value{ iarg } { } // Sets m_value.i to iarg
private:
value m_value;
};
Note also that I have used the {...} syntax for the initializer, rather than the (...) 'old style' and that I have used an argument name that is not the same as a union member.
Related
I am writing a C++ struct which contains a C-struct. The C-struct is included by other .c files, so I cannot change it to C++.
I want to make sure that every member is of the c++ struct is initialized.
So I have used in-class initialization and constructor initilizer where needed:
struct CppStruct
{
CStruct pod {}; // initialize all members to 0
int i = 0;
double d = 0.0;
CppStruct()
{ }
CppStruct(int another_val)
: i(another_val)
{ }
};
This initializes all the members of the CStruct to zeroes.
Zeroes are fine for most members of the c-struct,
but unfortunately, it also contains a C-enum whithout a zero-value:
// C-header
enum Color { // no '0' entries here!
red = 1,
yellow = 2;
};
struct CStruct { // this struct can potentially contain a lot of members
int i;
int j;
Color col;
int m;
int n;
};
The only way I have found to write the constructor is this, but this theoretically sets the pod.col member twice:
CppStruct()
{ pod.col = Color::red; }
CppStruct(int another_val)
: i(another_val)
{ pod.col = Color::red; }
Is there anyway I can override the initialization of selected members of the pod, without having to specify all its members?
e.g. I tried this but it does not compile:
CppStruct() : pod.col(Color::red) {}
The following is legal, but I want to avoid it,
in case the CStruct is changed/shuffled by another colleague:
CppStruct() : pod{0,0,Color::red,0,0} {}
The best way I think is to just overwrite the col value inside the constructor, don't worry about multiple initializations, as it's just an enum, not a massive object, so the performance difference is somewhat nothing (unless you are really desperate for performance).
A quick and dirty way to achieve initialization the way you wanted is to create a static function that would return a default CStruct like that:
struct CppStruct
{
CStruct pod {}; // initialize all members to 0
int i = 0;
double d = 0.0;
CppStruct()
: pod(_get_default_pod())
{ }
CppStruct(int another_val)
: i(another_val), pod(_get_default_pod())
{ }
private:
static inline CStruct _get_default_pod() {
CStruct pod {};
pod.col = Color::red;
return pod;
};
};
struct Value {
struct Array;
struct Dict;
struct Primitive;
Value() {}
virtual ~Value() {}
virtual Array * asArray() { assert(false); }
virtual Dict * asDict() { assert(false); }
virtual Primitive * asPrimitive() { assert(false); }
int asInt();
double asDouble();
std::string asDate();
std::string asString();
};
struct Value::Array : public Value {
std::vector<Value> m_data;
Array() {}
~Array() {}
Value::Array * asArray() {
Value::Array * result = this;
return result;
}
};
The statement Value::Array * result = this; is giving me this error...
E0144 a value of type "Value::Array *" cannot be used to initialize an entity of type "Value::Array *".
The problem can be seen in much simpler code
enum SPELLSTATUS { NEW, FAIL, OK } spellStatus = SPELLSTATUS::NEW;
or
enum SPELLSTATUS { NEW, FAIL, OK } spellStatus = NEW;
E0144 a value of type "SPELLSTATUS" cannot be used to initialize an entity of type "SPELLSTATUS" NcEdit D:\Systems\Editor2019\Spell.cpp 30
VS2019.
Compiles and runs just fine.
I wonder if there is a workaround is such situation:
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
}
//...
A a; //crash
//...
I suppose it is caused by order of initialization. Variable B is initilized by calling an uninitilized std::function instance, hence the crash. By my logic, the workaround would be to initialize std::function first, then initialize member B. But then, such code is not valid:
class A
{
//error: 'B' was not declared in this scope
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
}
I tried to make to make the std::function static, and such code works, but requires non-constexpr/const member, because std::function has non-trivial destructor - which is bad, because that requires source file, which requires creating such file, which requires some efford and destruction of my beautiful header-only class hierarchy! (I mean, I could be lazy and define this variable in the header, but then the multiple definition problem occurs). I know it might be a bad design (i'm just testing things out), but do you have any ideas how the problem can be solved without involving source files?
Although your example is contrived, there are times when I've needed (or its more convenient) to initialize complex objects in a similar way.
But, why use std::function<>? Why not just use a function?
class A
{
class
{
public:
void setValue(int val) { i = val; }
private:
int i;
} B = initB(10);
static decltype(B) initB(int value)
{
decltype(B) temp;
temp.setValue(value);
return temp;
}
};
Although, I wouldn't normally use decltype(B); I would just give the class a name.
I feel like I am somehow subverting your intent, but if you initialize the variables in the constructor, you can make things work.
#include <functional>
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B;
std::function<decltype(B)(int)> initB;
public:
A() {
initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
B = initB(10);
}
};
int main() {
A a;
}
A::initB is a value. It's not initialized at the point where you call it, because initialization is done (loosely speaking) in the order you specify member fields. You can verify this by executing the below, which works:
#include <iostream>
#include <functional>
using namespace std;
template<typename T, typename U>
T set(T& tgt, const U& src)
{
new(&tgt) T(src);
return tgt;
}
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = set(initB, [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;})(10);
std::function<decltype(B)(int)> initB;
};
int main() {
A a;
}
I want to initialize array-of-classes member of a class
const int count = 5;
class In
{
float rate;
public:
In( int index )
{
rate = index / count;
}
};
class Out
{
In ins[count];
public:
Out() : /* ??? */
{
}
};
Can I obtain index of instance of In in initialization ins if I will rely on initialization list of Out::Out()
You can't do that. You need to define a default constructor for In.
Or better yet, use a std::vector.
EDIT: Might be supported in C++11, not sure though.
I have a struct:
struct s
{
UINT_PTR B_ID;
};
s d;
d.B_ID=0x1;
That works fine, but I want d.B_ID to be constant. I tried to use (const) but it didn't work. So after I put a value to d.B_ID, then I want make it a constant.
Any ideas?
EDIT
ok i don't want the whole struct a constant.
when i set timer and use the b.B_ID as an idea for the timer.
in the
switch(wparam)
{
case b.B_ID // error: B_ID must be constant
....
break;
}
so that is why i need it to be a constant
Variable modifiers are fixed at compile time for each variable. You may have to explain the context of what you are trying to do, but perhaps this will suit your needs?
struct s
{
int* const B_ID;
};
int main (void) {
int n = 5;
s d = {&n};
int* value = d.B_ID; // ok
// d.B_ID = &n; // error
return 0;
}
Since you are using C++ I would recommend:
class s {
public:
int* const B_ID;
s (int* id) :
B_ID (id) {
}
};
void main (void) {
int n = 5;
s my_s_variable = s(&n);
int* value = my_s_variable.B_ID; // ok
//my_s_variable.B_ID = &n; // error
return 0;
}
Ramiz Toma: well i need way to do it using the s.B_ID=something
In C/C++ type modifiers (like const) are declared at run time for a given type and cannot be changed at run time. This means that if a variable is declared const it can never be assigned to using the assignment operator. It will only be assigned a value when it is constructed.
This is not a problem however because you can always get around this by proper design.
If you say you need to use assignment, I assume that this is because you create the struct before you know what the value of the variable will be. If this is the case then you simply need to move the struct declaration till after you know the value.
For example
s d; //variable declaration
//calculate B_ID
//...
int* n = 5;
//...
d.B_ID = &n;
This will not work, because if you want b.D_ID to be 'un assignable' it will always be so. You will need to refactor your code similarly to:
//calculate B_ID
//...
int* n = 5;
//...
s d (&n);
//good
struct s
{
s() : B_ID(0){}
UINT_PTR const B_ID;
};
int main(){
s d;
d.B_ID=0x1; // error
}
EDIT: Sorry, here is the updated code snippet in C++
struct s
{
s(UINT_PTR const &val) : B_ID(val){}
UINT_PTR const B_ID;
};
int main(){
s d(1);
d.B_ID=0x1; // error
}
In C++ language the case label must be built from an Integral Constant Expression (ICE). ICE is what the compiler implies under the term "constant" in your error message. A non-static member of a class cannot be used in an ICE. It is not possible to do literally what you are trying to do. I.e. it is not possible to use a struct member in a case label.
Forget about switch/case in this context. Use ordinary if branching instead of switch statement.
You can't do that - ie. it is not possible to selectively make a single member of a struct const. One option is to 'constify' the entire struct:
s d;
d.B_ID=0x1;
const s cs = s; // when using this B_ID won't be modifiable - but nor would any other members
Or you could set it at construction:
struct s
{
s(UINT_PTR const p): B_ID(p) {}
UINT_PTR const B_ID;
};
s d(0xabcdef);
Another way would be a getter and a one time setter
class s
{
private:
bool m_initialized;
UINT_PTR m_value;
public:
s() : m_initialized(false), m_value(NULL) {}
s(UINT_PTR value) : m_initialized(true), m_value(value) {}
//no need for copy / assignment operators - the default works
inline UINT_PTR GetValue() const { return m_value; } //getter
bool SetValue(UINT_PTR value) //works only one time
{
if (m_initialized)
{
m_value = value;
m_initialized=true;
return true;
}
else
{
return false;
}
}
inline bool IsInitialized() const { return m_initialized; }
};