Add structure(s) to QList in for-loop - c++

I fill a structure in a loop and per loop i want to have a new instance (copy) in a Qlist of this instance.
I read data out of a (xml)file and will store the data in that QList.
After eg. 4 loops, the QList contains only one structure ...
typedef struct structure_Anf
{
public:
typedef struct structure_Art
{
public:
QString Art = "";
}
structure_Art_t;
QString Num = "";
QList <structure_Art_t> ArtList;
}
structure_Anf_t;
QList <structure_Anf_t> FullAnfList; // holds the full list of structures
structure_Anf_t struc_act_Anf; // holding actual used instance of structure
void test
{
for ( int i=0; i < 5; i++) // add some data
{
struc_act_Anf = {};
struc_act_Anf.Num = "foo" + i;
structure_Anf_t::structure_Art_t struc_new_Art;
for (int x = 0; x < 3; x++) // add some data to Art
{
struc_new_Art.Art = "bar" + x;
ArtList.append (struc_new_Art);
}
FullAnfList.append (struc_act_Anf);
}
}
Edit: Some minor changes on the code.
As i wrote above, after i-times-loop, FullAnfList.count() = 1 and not 5 as expected.

I do not have Qt , I convert it to Std c++ it works properly:
#include <iostream>
#include <list>
using namespace std;
using QString = std::string;
template <typename T>
using QList = std::list<T, std::allocator<T>>;
typedef struct structure_Anf
{
public:
typedef struct structure_Art
{
public:
QString Art = "";
}
structure_Art_t;
QString Num = "";
QList<structure_Art_t> ArtList;
}
structure_Anf_t;
QList <structure_Anf_t> FullAnfList;
structure_Anf_t struc_act_Anf; // holding actual used instance of structure
void test()
{
for (auto i : { 1,2,3,4,5,6 })
{
struc_act_Anf = {};
struc_act_Anf.Num = "foo";
structure_Anf_t::structure_Art_t struc_new_Art;
for (auto i : { 1,2,3,4,5,6})
{
struc_new_Art.Art = "bar";
struc_act_Anf.ArtList.push_back(struc_new_Art);
}
FullAnfList.push_back(struc_act_Anf);
}
}
int main()
{
test();
std::cin.get();
}

Related

Accessing Member Variables of Derived Structs Without Casting

I have a bunch of derived structs. Is there any way for me to access the derived width without casting?
If I do this, I get 1s and not 42 and 13:
#include <iostream>
#include <deque>
using namespace std;
struct BaseParams {
virtual ~BaseParams() {}
int width = 1;
};
struct VectorParams : BaseParams {
int width = 42;
};
struct MatrixParams : BaseParams {
int width = 13;
};
int main()
{
std::deque<BaseParams *> params;
VectorParams *vectorParams = new VectorParams;
MatrixParams *matrixParams = new MatrixParams;
params.push_back(vectorParams);
params.push_back(matrixParams);
for (auto &param : params) {
std::cout << param->width << std::endl;
}
// Don't want to do this
// for (auto &param : params) {
// MatrixParams *matrixParams = dynamic_cast<MatrixParams *>(param);
// if (matrixParams)
// std::cout << matrixParams->width << std::endl;
// VectorParams *vectorParams = dynamic_cast<VectorParams *>(param);
// if (vectorParams)
// std::cout << vectorParams->width << std::endl;
// }
return 0;
}
If possible, I want to avoid casting because I have so many derived structs.
To overwrite the width in BaseParams, instead of making a new variable, you can give VectorParams a constructor like this:
struct VectorParams : BaseParams {
VectorParams() {
width = 42;
}
};
In fact constructors are always how variables are set in new objects. When you write
struct BaseParams {
virtual ~BaseParams() {}
int width = 1;
};
the compiler actually turns it into a constructor, similar to
struct BaseParams {
virtual ~BaseParams() {}
int width;
BaseParams() {
width = 1;
}
};

How to pass an object data member to a lambda function in C++?

Let's say I have the following non-working code (just for illustration purposes):
class fruit
{
public:
std::string apple;
std::string banana;
std::String orange;
};
class grocery
{
public:
std::vector<fruit> g_items;
std::string total_weight;
};
std::vector<grocery> shopping;
auto check_item = [&](std::string f_itm) -> void
{
for (std::size_t i = 0; i < shopping.g_items.size(); ++i)
{
std::cout << shopping.g_items.at(i).f_itm << std::endl;
}
};
check_item(apple);
check_item(banan);
check_item(orange)
How can I call the lambda function check_item, passing specific data members of the fruit object, since they all have the same type (std:string)?
Thank you.
Try this:
#include <string>
#include <vector>
#include <iostream>
class fruit
{
public:
std::string apple;
std::string banana;
std::string orange; //std::string, not std::String
};
class grocery
{
public:
std::vector<fruit> g_items;
std::string total_weight;
};
std::vector<grocery> shopping;
auto check_item = [&](std::string(fruit::* f_itm)) -> void
{
for (std::size_t i = 0; i < shopping.size(); ++i) //you have two, vectors, so first iterate through shopping
{
for (std::size_t j = 0; j < shopping[i].g_items.size(); ++j) //then, iterate through g_items
std::cout << shopping[i].g_items[i].*f_itm << std::endl; //then, print
}
};
int main() {
check_item(&fruit::apple);
check_item(&fruit::banana); //you put banan, not banana
check_item(&fruit::orange); //remember the ;
}
Your original code had a couple of errors. Then, in your for loop, you have two iterate through both vectors, as the comments explain. Then, it should work.
Change the lambda to take in a pointer-to-member, eg:
class fruit
{
public:
std::string apple;
std::string banana;
std::string orange;
};
class grocery
{
public:
std::vector<fruit> g_items;
std::string total_weight;
};
std::vector<grocery> shopping;
...
auto check_item = [&](std::string (fruit::*f_itm)) -> void
{
for (auto &g : shopping)
{
for (auto &f : g.g_items) {
std::cout << f.*f_itm << std::endl;
}
}
};
check_item(&fruit::apple);
check_item(&fruit::banana);
check_item(&fruit::orange);
Demo

How to concatenate name of variables in Cpp?

I have class Walls in my program. Inside of class are objects Wall1, Wall2 etc.
I want to do something like this:
class definition:
class Walls {
public:
Walls(){
nPositionX = nMapWidth - 1;
nHoleSize = 1;
nHolePosition = rand()%(nMapHeight - nHoleSize);
count++;
}
static int getCount() {
return count;
}
int getPositionX()
{
return nPositionX;
}
private:
int nPositionX;
int nHolePosition;
int nHoleSize;
static int count;
};
access to object
for (int i = 0; i < Walls::getCount(); i++) {
int nPosx = Wall"i".getPositionX();
}
}
Is that possible in c++?
Ok big thanks for everyone for help. I don't know why I didn't tried it before.
You can use an array or std::vector for that, eg:
std::array<Wall, MAX_WALLS> m_walls;
or
std::vector<Wall> m_walls;
...
// initialize m_walls[0], m_walls[1], etc as needed...
...
for (size_t i = 0; i < m_walls.size(); i++) {
int nPosx = m_walls[i].getPositionX();
...
}
Or, you can use a std::map, eg:
std::map<std::string, Wall> m_walls;
...
// initialize m_walls["Wall1"], m_walls["Wall2"], etc as needed...
...
for (int i = 1; i <= getCount(); i++) {
int nPosx = m_walls["Wall" + std::to_string(i)].getPositionX();
...
}
The code is not executed until you execute your program, but in the executable there are no variable names anymore. Hence, no.
You can use an array or vector:
struct Wall { int get_position() const { return 42; } };
using Walls = std::vector<Wall>;
Walls walls;
for (const auto& wall : walls) {
int nPosx = wall.get_position();
}
Or if you really want to map names to objects, use a std::map:
std::map<std::string,Wall> named_walls;
named_walls["stone wall"] = Wall();

How to transfer a class type to a function template for new operation as a parameter?

I have a piece of c++ code:
#include <iostream>
#include <string>
#include <map>
static counter = 0;
class Probe
{
private:
int supply_;
Probe(const Probe&);
public:
Probe()
{
supply_ = 10000;
}
int get_supply()
{
return supply_;
}
};
/********************************************************************************
template<class T> T Create(int counter, T& produced)
{
produced[counter] = new ; // ??????????????????????????????????????
return produced;
}
************************************************************************************/
std::map<int, Probe*> CreatInitWorkers(int counter, std::map<int, Probe*> &init_workers)
{
init_workers[counter] = new Probe();
return init_workers;
}
int main()
{
std::map<int, Probe*> workers;
for (int i = 0; i < 12; i++)
{
workers = CreatInitWorkers(worker_counter++, workers);
}
for (auto it : workers)
{
std::cout << it.first << std::endl;
}
}
I want to create a template function (as it shows between the stars) like the CreatInitWorkers function. But I don't know how to transfer the Probe class to the new operation because for my program there are still other classes needed to be there. Is there any way can do it? Thanks.
Something along these lines:
template<class T> T Create(int counter, T& produced)
{
using C = std::remove_pointer_t<std::decay_t<decltype(produced[counter])>>;
produced[counter] = new C();
return produced;
}
Demo

A vector for different classes

I have a class with a vector I'd like to fill with one of two types of class, selected by the user. Let's call my classes option1 and option2
What I'd like to do it something like
class storage_class
{
public:
storage_class(int sel, int n)
{
if(sel == 1)
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<option1>());
else if(sel == 2)
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<option2>());
}
private:
// Something like this but that actually works
std::vector<T> my_store;
};
Then I'd like to use it like this, or something similar, so there's no need to modify this usage dependent on the option chosen.
int main()
{
storage_class store(1);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
The classes option1 and option2 will be mathematical simulations that will be creating data and themselves store this data in a vector that are members of the class.
I want to store multiple instances of either option in a vector and then manipulate them from there. I can use C++17.
As you have c++17 in use, you can simply use a std::variant as type for the container which itself can keep all types you want to have.
Example:
class A { public: void Do() { std::cout << "A::Do" << std::endl; } };
class B { public: void Go() { std::cout << "B::Go" << std::endl; } };
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
int main()
{
std::vector<std::variant<A,B>> vec;
vec.push_back(A{});
vec.push_back(B{});
for ( auto& el: vec)
{
std::visit( funcs{ [](A& a){ a.Do(); }, [](B& b) { b.Go(); } }, el);
}
}
Output:
A::Do
B::Go
The classes are fully independent and the methods can be simply called with std::visit and passing a callable object herein. I provide a simple funcs implementation, which simply collect all callable entities to simplify to interface the call to different methods of different unrelated classes here.
As std::variant is some kind of a tagged union, it needs the storage for the biggest type you have in use. If this wastes to much memory, you can store a pointer to the instance instead, maybe with std::unique_ptr or std::shared_ptr if you like some assistance for memory management ;)
Here is an example that tries to stay as close to your example as it can using a template parameter on class storage_class. See working version here. I've added only option1 and made the member my_store public as you access it in your main function.
#include <memory>
#include <vector>
#include <iostream>
struct option1{
void create_data(){ std::cout << "created\n"; }
};
template<typename T>
class storage_class
{
public:
storage_class(int n)
{
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<T>());
}
std::vector<std::unique_ptr<T>> my_store;
};
int main()
{
storage_class<option1> store(4);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
another option would be to use std::variant. See workign version here.
#include <memory>
#include <vector>
#include <variant>
#include <iostream>
struct option1{
void create_data(){ std::cout << "created 1\n"; }
};
struct option2{
void create_data(){ std::cout << "created 2\n"; }
};
class storage_class
{
public:
using option = std::variant<std::unique_ptr<option1>,std::unique_ptr<option2>>;
storage_class(int sel, int n)
{
if(sel == 0)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option1>()));
else if(sel == 1)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option2>()));
}
std::vector<option> my_store;
};
int main()
{
storage_class store(1, 4);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
std::get<1>(store.my_store[i])->create_data();
}
}
Standard way is to make option1 and option2 derived classes from a base_class which seems consistent with your sample main(). Using a generic Factory class template, here is an example:
#include <functional>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option1." << std::endl;
}
};
class option2 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option2." << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, []() { return std::make_unique<option1>(); } }
, { 2, []() { return std::make_unique<option2>(); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store(1, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
This compiled for me on linux using g++ -std=c++17 main.cc.
There are improvements that can be made to this code, but I copied your main() function in order to illustrate the basic idea(s). Hope that helps.
Edit 21 Sept 2018 - Example of how to pass parameters into constructors.
File: factory.h
#pragma once
#include <functional>
#include <memory>
#include <unordered_map>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
File: main.cc
#include "factory.h"
#include <iostream>
#include <string>
#include <vector>
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
const double mD;
public:
option1(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option1: mD("<<mD<<')' << std::endl;
}
};
class option2 : public base_class
{
const double mD;
public:
option2(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option2: mD("<<mD<<')' << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class,double>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, [](double d) { return std::make_unique<option1>(d); } }
, { 2, [](double d) { return std::make_unique<option2>(d); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel,static_cast<double>(i)));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store1(1, n_iterations);
storage_class store2(2, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store1.my_store[i]->create_data();
store2.my_store[i]->create_data();
}
}
Output:
I'm option1: mD(0)
I'm option2: mD(0)
I'm option1: mD(1)
I'm option2: mD(1)
I'm option1: mD(2)
I'm option2: mD(2)
I'm option1: mD(3)
I'm option2: mD(3)