Do the same operation on different variables based on the variant? - c++

I need to same operation on an array of struct based on the variant. In compile time I know which array of struct should be updated using one generic function. Is inheritence is good, like I have 4 variants and 4 derived classes, every class sets a variable and the function updates corresponding array?
Or no inheritance and assign the right array in compile time?
Variant 1
Function has to update array1
Variant 2
Function has to update array2
…
…
array4
I tried to assign like
#ifdefined variant 1
typedef array array1
//array =array1;
#elifdefined variant 2
typedef array array2
This was not accepted.

As you know the type in compile time, you can use if constexpr and std::is_same in the function that updates the values.
typedef std::vector<bool> Array1;
typedef std::vector<int> Array2;
#define VARIANT 1
#if VARIANT==1
typedef Array1 Array;
#elif VARIANT==2
typedef Array2 Array;
#else
#error No suitable variant
#endif
void update(Array& parameter)
{
if constexpr (std::is_same_v<Array, Array1>) {
// Do something for Array1
}
else if constexpr (std::is_same_v<Array, Array2>) {
// Do something for Array2
}
else {
// No suitable type, #error should detect this
}
}

i did it simply like this :)
#include <iostream>
using namespace std;
int variant=1; //for test - in actual this comes from template
struct mystruct
{
int member1;
int member2;
};
struct mystruct array1[4];
struct mystruct array2[4];
int main() {
mystruct* array;
//few test calues
//fillup arrays for test
switch(variant)
{
case 1:
array = array1;
break;
case 2:
array= array2;
break;
case3: //reserved
break;
default:
break;
};
for (int i = 0; i < 3; i++) {
cout << array[i].member1 << "\n";
cout << array[i].member2 << "\n";
}
return 0;
}

Related

How do I create an std::array of immutable structs? I.e. structs with only const values [duplicate]

This question already has answers here:
Initialize an std::array algorithmically at compile time
(3 answers)
Populate An Array Using Constexpr at Compile-time
(4 answers)
Initialize array whose size is a compile-time constant to single value
(3 answers)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Say I have struct S:
struct S {
const int i;
const bool b;
}
And I want to create an (non-const) array of this struct like so:
std::array<S, 16> arr;
for(int i = 0; i<arr.size(); i++)
arr[i] = { i, i%2==0 };
Then the compiler will complain that I didn't initialize the a const variable when I initialized the array.
I tried doing it with a vector as an intermediary. But int the function I'm writing I have to pass the original array in another struct, and return that other struct.
struct OtherStruct {
const std::array<S,16> sArray;
};
OtherStruct f() {
std::vector<S> vec(16);
for(int i = 0; i<16; i++)
vec.push_back({ i, i%2==0 });
return { vec.data() };
}
But that didn't work either. I hoped that passing the pointer to the vector data would be cast into a C-style array, from which an std::array could be made. What is the cleanest way to fix this?
I'm working with C++11.
Note that this example is a gross simplification. The line arr[i] = { i, i%2==0 }; would be replaced by a function that parses incoming network data. The actual array is way bigger and the struct is also more complicated. None of the data that will populate the struct will be known at compile time, only the layout.
You can use parameter pack expansion to create an initialiser list of arbitrary size.
You will need to backport std::index_sequence into C++11
template <size_t... Is>
std::array<S, sizeof...(Is)> make_s_array_impl(index_sequence<Is...>) {
return { { { Is, Is % 2 == 0 }... } };
}
template <size_t N>
std::array<S, N> make_s_array()
{
return make_s_array_impl(make_index_sequence<N>{});
}
See it live
As the number of values is known in the compile time, you can fill the array with an initializer list. You can create it easily with BOOST_PP_REPEAT:
#include <boost/preprocessor/repetition/repeat.hpp>
struct S {
const int i;
const bool b;
};
struct OtherStruct {
const std::array<S,16> sArray;
};
OtherStruct f() {
#define FILL(z, i, ignored) { i, i%2==0 },
return {std::array<S,16>{{
BOOST_PP_REPEAT(16, FILL, ignored)
}}};
#undef FILL
}
In C/C++ when you use the const keyword you cannot left the variable uninitialized when you declare it and neither assign a new value after this is declared.
For example:
const int i = 5; //this is a correct way to use the const keyword
const int i;
...
i = 5; //this is NOT a correct way to use the const keyword
However, you can use const_cast<T> to bind a pointer of the same type to the value of your struct instance and change it only once in the for loop.
In this way you can obtain what you asked.
#include <iostream>
#include <array>
struct S{
const bool b = 0; //Intialize the values in order to avoid compiler errors.
const int i = 0;
};
int main(){
std::array<struct S, 16> arr;
for(int i = 0; i<arr.size(); i++){
// declare a variable that point to the const value of your struct instance.
bool* b = const_cast <bool*> (&arr[i].b);
int* in = const_cast <int*> (&arr[i].i);
*b = i; //change the value with the value you need.
*in = i%2==0;
}
for(int i = 0; i<arr.size(); i++){
int a = i%2==0;
std::cout<< "const bool: " << arr[i].b << " " << (bool)i << "const int: " << arr[i].i << " " << a << std::endl;
}
}

Can I "browse" members of a struct to simplify building a BDD class?

I am building a custom BDD class to store different types of data (e.g., long, char*, double, …) for my program.
In order to store the data, I need a struct for each table, like this:
struct MYSTRUCT0
{
char variable0[10];
char variable1[70];
};
struct MYSTRUCT1
{
long variable0;
long variable1;
char variable2[6];
double variable3;
};
But it's much work each time I need a new table, because I need to write a function to save each table in a file, to read it, etc. Worse, it's not really object-oriented.
So my question is, is there a way to "browse" the struct to simplify my code?
Something like this:
for(int v=0; v<arraysize; v++)
for(int i=0; i<MYSTRUC0.length; i++)
{
if (MYSTRUCT.getvar(i).type == long)
DoSomethingForLong(myarray(v).getval(i));
if (MYSTRUCT.getvar(i).type == char*)
DoSomethingForCharPtr(myarray(v).getval(i));
}
I know it's possible for code like this to work directly in C++. I just use it to illustrate what I mean.
Below code is just an example of how you can make your own "variable-type-aware" struct that maybe what you want:
#include <vector>
enum MyTypes
{
LONG,
CHARPTR,
DOUBLE,
} myTypes;
struct MyStruct
{
MyStruct(long longVar)
{
variable.longVar = longVar;
whichType = LONG;
}
MyStruct(char* charPtr)
{
variable.charPtr = charPtr;
whichType = CHARPTR;
}
MyStruct(double var)
{
variable.var = var;
whichType = DOUBLE;
}
~MyStruct()
{
}
MyTypes whichType;
union {
long longVar;
char* charPtr;
double var;
} variable;
};
void DoSomethingForLong(MyStruct* doubleStruct)
{
/*Do something specific to long*/
};
void DoSomethingForCharPtr(MyStruct* doubleStruct)
{
/*Do something specific to char pointer*/
};
void DoSomethingForDouble(MyStruct* doubleStruct)
{
/*Do something specific to double*/
};
int main()
{
std::vector<MyStruct*> myVec;
// add a struct with long variable
long longVar = 2000000000;
MyStruct* myLongStruct = new MyStruct(longVar);
myVec.push_back(myLongStruct);
// add a struct with char pointer
char* charArray = new char[1000];
MyStruct* myCharPtrStruct = new MyStruct(charArray);
myVec.push_back(myCharPtrStruct);
// add a struct with double variable
double doubleVar = 200.200;
MyStruct* myDoubleStruct = new MyStruct(doubleVar);
myVec.push_back(myDoubleStruct);
for (int i = 0; i < myVec.size(); ++i)
{
MyStruct* tempStruct = myVec[i];
if (tempStruct->whichType == LONG)
{
DoSomethingForLong(tempStruct);
}
else if (tempStruct->whichType == CHARPTR)
{
DoSomethingForCharPtr(tempStruct);
}
else if (tempStruct->whichType == DOUBLE)
{
DoSomethingForDouble(tempStruct);
}
}
if (myLongStruct)
{
delete myLongStruct;
myLongStruct = nullptr;
}
if (myCharPtrStruct)
{
if (charArray)
{
delete[] charArray;
charArray = nullptr;
}
delete myCharPtrStruct;
myCharPtrStruct = nullptr;
}
if (myDoubleStruct)
{
delete myDoubleStruct;
myDoubleStruct = nullptr;
}
}
If you go to the trouble of adding a member function that can export your data members as a tuple, then we can use some template meta programming to make this work.
Live Demo (C++14)
First, the alteration:
struct MYSTRUCT0
{
char variable0[10];
char variable1[70];
std::tuple<char(&)[10], char(&)[70]> GetData()
{
return std::tie(variable0, variable1);
}
};
struct MYSTRUCT1
{
long variable0;
long variable1;
char variable2[6];
double variable3;
std::tuple<long&, long&, char(&)[6], double&> GetData()
{
return std::tie(variable0, variable1, variable2, variable3);
}
};
std::tie will put references to these members into a tuple.
The nice thing about a tuple is that it encodes all the types into a list that we can take advantage of. (You could probably write macro(s) to create these structs for you.)
From here the strategy is to write a function that can process any tuple.
Since we access elements of a tuple with a call to std::get<i> where i is some index, we need a way to get indices for these elements, so we introduce a level of indirection to create them using a std::index_sequence:
template<class... T>
void ProcessData(const std::tuple<T...>& data){
std::cout << "Processing " << sizeof...(T) << " data elements...\n";
detail::ProcessDataImpl(data, std::make_index_sequence<sizeof...(T)>{});
}
The definition of detail::ProcessDataImpl is going to use a technique called simple pack expansion. It's a trick where we take advantage of array initialization to call a function for each element in a parameter pack. It looks a little weird, but bear with me:
template<class... T, size_t... I>
void ProcessDataImpl(const std::tuple<T...>& data, std::index_sequence<I...>){
using swallow = int[];
(void)swallow{0, (void(ProcessElement(std::get<I>(data))), 0)...};
}
This will call a function called ProcessElement for each element in the tuple. We use the comma operator and void casting to ensure that the function doesn't really do anything, and all our operations are solely for their side effects (calling our ProcessElement function).
Our ProcessElement function will use yet another level of indirection to pass on the argument for processing for more complicated types like our character arrays. Otherwise we can overload it for the types that we need:
template<class T>
struct ProcessElementImpl
{
static void apply(const T& element)
{
static_assert(sizeof(T) == 0, "No specialization created for T");
}
};
template<size_t N>
struct ProcessElementImpl<char[N]>
{
static void apply(const char(&arr)[N])
{
std::cout << "Process char array of size " << N << std::endl;
}
};
template<class T>
void ProcessElement(const T& element)
{
ProcessElementImpl<T>::apply(element);
}
void ProcessElement(long _element)
{
std::cout << "Process a long\n";
}
void ProcessElement(double _element)
{
std::cout << "Process a double\n";
}
Notice that we overloaded for long and double, but we passed it along to ProcessElementImpl for our character array. This is required because we cannot partially specialize a template function, and we want to process arbitrarily-sized arrays.
The base class template also contains a static_assert so that we're forced to write a specialization for exporting a data type.
Finally we can call it like so:
int main()
{
MYSTRUCT0 struct0;
ProcessData(struct0.GetData());
MYSTRUCT1 struct1;
ProcessData(struct1.GetData());
return 0;
}
Output:
Processing 2 data elements...
Process char array of size 10
Process char array of size 70
Processing 4 data elements...
Process a long
Process a long
Process char array of size 6
Process a double

c++ how to initialize const elements of an array

i need a way to initialize const elements of an array for the program i am currently working on.
The problem is that i have to initialize these elements with a function, there is no way to do it like this:
const int array[255] = {1, 1278632, 188, ...};
because its alot of data i have to generate.
What i tried is to memcpy data to the const int's but that can't work and hasn't worked.
const int array[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, array[i]);
}
}
I hope you understand what i am trying, sorry if i doubled the question, i must have overlooked it.
How about this?
#include <array>
typedef std::array<int, 255> Array;
const Array array = generateData();
Array generateData(){
Array a;
for(int i = 0; i < a.size(); i++) {
initializeSomehowTo(a[i]);
}
return a;
}
The easiest approach is to get the filled array from a function and use that to initialize your const (or constexpr) object. However, built-in arrays can't be copied but std::array<T, N> be:
std::array<T, 255> array = initializeData();
If you need a built-in array, I can imagine initializing a static member of a class (template, actually) where the index is expanded from indices expanded from an std::make_index_sequence<255> and used as positional argument in the array, i.e., something along these lines:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
int some_function(std::size_t i) { return i; }
template <typename> struct initialized_array_base;
template <std::size_t... I>
struct initialized_array_base<std::index_sequence<I...>> {
static const int array[sizeof...(I)];
};
template <std::size_t... I>
int const initialized_array_base<std::index_sequence<I...>>::array[sizeof...(I)]
= { some_function(I)... };
struct initialized_array
:initialized_array_base<std::make_index_sequence<256>> {
};
int main() {
std::copy(std::begin(initialized_array::array),
std::end(initialized_array::array),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
You can create a writable array, initialize it, and, then, create a const reference to it.
int arry[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, arry[i]);
}
}
const int (&array)[255] = arry;

passing struct pointers to functions c++

Should be a simple question, I have a struct
struct Foo{
float *bar;
Foo(){
bar = 0;
}
};
and a load function:
bool loadFoo(Foo *data){
float nums[4] = {0,1,2,3};
data->bar = nums;
return true;
};
And I run it like this:
void main(){
char data;
Foo myFoo;
loadFoo(&myFoo);
std::cerr << sizeof(myFoo.bar) << "\n";
std::cerr << myFoo.bar[0] << "\n";
std::cerr << myFoo.bar[1] << "\n";
std::cerr << myFoo.bar[2] << "\n";
std::cerr << myFoo.bar[3];
std::cin >> data;
};
and the output is 4 bytes for the sizeof(myFoo->bar) I thought by passing the struct to the method I could modify data->bar and since bar is, float *bar; I could make it an array since I cant specify that bar is an array because its an 'unknown size' when loaded. (when implemented the program will read in values from a file) This works fine with non pointer variables but its the pointer that I can't seem to understand.
How do I make it so that when I pass the struct I can modify the variable pointer?
any help would be greatly appreciated!
You can do something like you've specified, but the exact implementation you've given will encounter undefined behavior.
bool loadFoo(Foo *data){
// Create an array of 4 floats ON THE STACK.
float nums[4] = {0,1,2,3};
// point data->bar at the above slice of stack.
data->bar = nums;
return true;
// abandon the piece of stack we're pointing at.
}
You might want to look into std::vector as a growable way of storing runtime sizes arrays, or you will need to allocate backing store for the destination floats, e.g.
data->bar = new float[4];
and free it when you are done with it
delete data->bar;
That said; it would seem more elegant to do these operations as members of Foo.
#include <vector>
// #include <algorithm> // (for the std::copy option)
class Foo
{
std::vector<float> m_floats;
public:
Foo() : m_floats() {}
void loadFloats()
{
m_floats = { 0, 1, 2, 3 };
}
// or load them from someplace else
void loadFloats(float* srcFloats, size_t numFloats)
{
m_floats.clear();
m_floats.reserve(numFloats);
// copy by hand:
for (size_t i = 0; i < numFloats; ++i) {
m_floats.push_back(srcFloats[i]);
}
// or just:
// std::copy(srcFloats, srcFloats + numFloats, m_floats);
}
};
You haven't specified the problem but let me guess - it crashes and/or doesn't yield the result you expect. The reason for that is assigning a pointer to a local variable in the line data->bar = nums; Here you link your data->bar to a nums array which is allocated on stack and is freed when you exit loadFoo. The result is a dangling pointer inside your Foo object.
You can solve this in different ways. The most straightforward would be to use a constructor with size parameter - this will solve your unkonwn size issue. You'll need to explicitly allocate memory for the data->bar and copy the data into the allocated space (of course, it will require to free it when not in use anymore). Same effect can be achieved by using your loadFoo func but using internal language features (constructor/destructor) is much cleaner.
Instead of loadFoo you can have constructor
struct Foo{
float *bar;
Foo( int size){
bar = new float[size]; //allocate memory
//... Initialize bar
}
~Foo() { delete bar;}
};
OR using initializer_list
#include <initializer_list>
struct Foo{
float *bar;
Foo( std::initializer_list<float> l){
bar = new float[l.size()]; //allocate memory
std::initializer_list<float> ::iterator it = l.begin();
size_t i=0;
for(;it!=l.end();++it,++i)
bar[i] = *it;
}
~Foo() { delete bar;}
};
Also, make sure you follow rule of three

Array in Struct, Pointers [C++ Beginner]

Coming from a Java, PHP background, I am trying to get into C++. I would like to store an array in a struct. My problem is specifying the size of the array after initialising the struct.
Here's my code for the struct:
struct SpriteAnimation {
// ...
int parts; // total number of animation-parts
unsigned int textures[]; // array to store all animation-parts
// ...
};
And here for the main function:
SpriteAnimation bg_anim;
bg_anim.parts = 3;
unsigned int *myarray = new unsigned int[bg_anim.parts];
bg_anim.textures = myarray;
What do I need to change to fix this?
In modern C++, you would use a dynamic container for the inner "array":
struct SpriteAnimation {
std::vector<unsigned int> textures; // array to store all animation-parts
size_t num_parts() const { return textures.size(); }
};
This is by far safer and more modular than anything you could try with manually allocated storage. Usage:
SpriteAnimation x;
x.textures.push_back(12); // add an element
x.textures.push_back(18); // add another element
SpriteAnimation y = x; // make a copy
std::cout << "We have " << x.num_textures() << " textures." std::endl; // report
struct SpriteAnimation {
// ...
int parts; // total number of animation-parts
unsigned int * textures; // array to store all animation-parts
// ...
};
You can use type name[] syntax only if you declare members inline.
Size of a struct must be known at a compilation time.
I worked around the issue through following code.It might be having design issues so please look it up the following code works for me.
#include <iostream>
using namespace std;
struct lol {
// ...
int parts; // total number of animation-parts
unsigned int *texture; // array to store all animation-parts
// ...
};
int main() {
// your code goes here
lol bg_anim;
bg_anim.parts = 3;
unsigned int *myarray = new unsigned int[bg_anim.parts];
bg_anim.texture = myarray;
return 0;
}
Forgive me for using lol instead of your specified name.Do tell me any issues.And help me if there are other issues in my code.
Thank you !! :)