C++ - How to Make Static Dictionary to Lookup Matrix - c++

I am trying to write a C++ class that allows me to access certain matrix elements by a string lookup. I wanted to create a 'static' class that can do this, such as:
#include <unordered_map>
namespace Mine {
static double AA[3][4] = {
{5.04964676394959,-0.693207030363152,0.0422140829479668,-0.000968959310672217},
{2.6044054979329,0.288475262243944,-0.0208805589126506,0.000380899394040856},
{-4.32707864788065,1.07090008760872,-0.0777874445746693,0.00165150952598117}
};
static unordered_map<std::string, double[3][4]> Mine::parameter_store = { {"AA", AA}};
With the idea being that I would have several matrices, and could look them up based on a key. However, this seems to totally and utterly fail with the following error:
error: object expression of non-scalar type 'double [3][4]' cannot be used in a pseudo-destructor expression
Is it possible to build a lookup table this way in C++?

#include <unordered_map>
#include <vector>
namespace Mine{
template<class T>
using Matrix = std::vector<std::vector<T>>;
Matrix<double> AA = {
{5.04964676394959,-0.693207030363152,0.0422140829479668,-0.000968959310672217},
{2.6044054979329,0.288475262243944,-0.0208805589126506,0.000380899394040856},
{-4.32707864788065,1.07090008760872,-0.0777874445746693,0.00165150952598117}
};
static std::unordered_map<std::string, Matrix<double>* > parameter_store = { {"AA", &AA}};
}
#include <iostream>
int main()
{
std::cout << (*Mine::parameter_store["AA"])[0][0] << std::endl;
std::cout << (*Mine::parameter_store["AA"])[0][1] << std::endl;
std::cout << (*Mine::parameter_store["AA"])[1][2] << std::endl;
}
output
5.04965
-0.693207
-0.0208806
The Matrix<> template used here causes each row to store its length even though that's redundant. You can avoid this by used a std::array (but then you're locked into each matrix having equal dimensions since that's part of the type information) or using some library like Boost that provides a multidimensional array. That's an extremely small inefficiency though and unless you know you need to it might be best to not worry about that.

You can try wrapping double[3][4] in a structure/class
structure myMatrix {
double arr[3][4];
//if you want to initialize it
myMatrix(double[3][4] p){
//copy matrix here
}
};

Related

Using `static` keyword with Structured Binding

I'm trying to use C++17 structured binding to return a pair of values and I want those values to be both static and const so that they are computed the first time the function they're in is called and then they maintain their uneditable values for the lifetime of the program. However when I do this I get the error: a structured binding cannot declare an explicit storage class error and I'm not sure why or how to fix it. A minimum working example is below.
#include <iostream>
#include <utility>
static const std::pair<double, double> pairReturn()
{
return {3,4};
}
int main()
{
static const auto [a, b] = pairReturn();
std::cout << a << std::endl;
std::cout << b << std::endl;
return 0;
}
The error is a bit confusing, but structured binding to static variables is just not supported with c++17. Either use a different solution, or c++2a. A different solution could just be an additional line:
static std::pair pr = pairReturn();
auto &[a, b] = pr;

Is there any way to iterate through a struct?

I would like to iterate through a struct which is defined in other library whose source is not under my control. So any lib which requires to define the struct with its own macros/adaptors like previous questions is not usable here. I found the closest way is using boost::hana. However, it still requires to fill up an adaptor before I can iterate through it. I attached an example here. I wonder is there any way I can automate the BOOST_HANA_ADAPT_STRUCT then I do not need to fill up all the struct member names in there (those structs in total have more than hundred members).
#include <iostream>
#include <boost/hana.hpp>
#include <typeinfo>
namespace hana=boost::hana;
struct adapt_test
{
std::string name;
int data;
};
BOOST_HANA_ADAPT_STRUCT(
adapt_test
, name
, data
);
auto names = hana::transform(hana::accessors<adapt_test>(), hana::first);
int main() {
hana::for_each(
names,
[] (auto item)
{
std::cout << hana::to<char const *>(item) << std::endl;
}
);
adapt_test s1{"a", 2};
hana::for_each(
s1,
[] (auto pair)
{
std::cout << hana::to<char const *>(hana::first(pair)) << "=" << hana::second(pair) << std::endl;
}
);
return 0;
}
You can use Boost Flat Reflection like:
struct adapt_test
{
std::string name;
int data;
};
adapt_test s1{"a", 2};
std::cout << boost::pfr::get<0>(s1) << std::endl;
std::cout << boost::pfr::get<1>(s1) << std::endl;
boost::pfr::flat_for_each_field(s1, [] (const auto& field) { std::cout << field << std::endl; } );
P.S. Respect for #apolukhin for this library.
The basic answer to your question is no.
C++ does not treat identifiers as string literal (it could be indeed useful in some cases), and there is no bridge unfortunately between these kind of strings.
Hopefully, some standard one day will bring this ability, relieving us from having to go through macros or code generation, or maybe doing differently like this: telling "please treat my struct A { int x, y; } as a pair", where the meaning would be to match type of first and second to the members x and y and then building the types so that it works, it would be really useful for tuples as well. A kind of structured template matching.
Currently the best that can be done to my knowledge is to match structs to tuple without the names (as of C++17) because of the above limitation, such as with boost::hana or boost::fusion as you do.

C++ Dynamic Array Member Variable Assignment

I am having a problem with assigning new values to a dynamic int array that is a data member variable of the class IntersectionFlowRate(). I can initialize and print the values of the array inside the constructor. However, when I exit the constructor to the another class and then later call a function within the IntersectionFlowRate() class passing in variables to overwrite the initial values of the data member it will segmentation fault. I have debugged to find that overwriting the array is causing the seg fault. And that even attempting to access the dynamic array within one of its functions will seg fault.
My question is how can I edit the values of a dynamic int array member variable from within one of its functions i.e setArrayElement(int index, int x).
Here is some of my code. Sorry if I am unclear or missing something ridiculous. I have been stuck on this for hours.
#ifndef INTERSECTIONFLOWRATE_H
#define INTERSECTIONFLOWRATE_H
class IntersectionFlowRate
{
public:
IntersectionFlowRate();
~IntersectionFlowRate();
void setFlowCycle(int index, int flow);
private:
int* m_flowRateMotorCycle;
};
#endif
in the .h file ^
#include "IntersectionFlowRate.h"
#include <cstdlib>
#include <iostream>
#include <new>
using namespace std;
IntersectionFlowRate::IntersectionFlowRate()
{
const int SIZE = 4; //Constant for m_flowRates[] size
//DYNAMIC MEMORY DELETE LATER
m_flowRateMotorCycle = new int[SIZE];
for(int i = 0; i < SIZE; i++){
m_flowRateMotorCycle[i] = 0;
cout << m_flowRateMotorCycle[i] << endl;
cout << "WE GOT HERE" << endl;
}
}
void IntersectionFlowRate::setFlowCycle(int index, int flow){
cout << "INDEX: " << index << endl;
cout << "FLOW: " << flow << endl;
m_flowRateMotorCycle[index] = flow; //seg fault is here
}
I have another class that creates a pointer to a IntersectionFlowRate() object and then calls its setFlowCycle function passing in two VALID ints. With the debugging I was able pass 0 and 3 to the function setFlowCycle(0, 3) just fine and output those variables within the function.
#ifndef TRAFFICSIM_H
#define TRAFFICSIM_H
#include "IntersectionFlowRate.h"
using namespace std;
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
~TrafficSim(); //Destructor
private:
IntersectionFlowRate* m_flowRate;
};
#endif
#include "TrafficSim.h"
#include "IntersectionFlowRate.h"
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
I replicated the error with this code. If no one else can I am completely unsure of what is possibly wrong anymore.
You are setting a local variable called m_flowRate, not the member variable m_flowRate of your TrafficSim class:
Instead of this:
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
It should be this:
TrafficSim::TrafficSim()
{
m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
But overall, it not need be a pointer. It could be an object member within your class. That would cut down on the pointer usage a bit:
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
private:
IntersectionFlowRate m_flowRate;
};
Then:
TrafficSim::TrafficSim()
{
m_flowRate.setFlowCycle(0, 3);
}
As to your question as to how to incorporate usage of std::vector in your class, here is a code sample of the IntersectionFlowRate class, rewritten using vector:
Vector sample
Also, another source of problems is that your classes fail to follow the Rule of 3 when you have pointers to dynamically allocated memory in your class.
Using std::vector takes care of this automatically, but if you insist on using pointers, you need to adhere to the directions at the link posted.
Yes, use a std::vector, it is much simpler, and it is a template so it also pretty fast and works any type (best for primitive types or pointers to objects) , and it also has boundary checking and other useful things.
If you need fast array-like access then you could use std::map which associates a key with a value, like so
std::map<UINT, YourClass*> m_mapIDs_to_YourClass;
When you first start using stl containers they might seem a little strange, but after a short while you cannot do without them, luckily they have been part of the C++ standard for some time now.
Boundary check for both these containers can be done by comparing your iterator to mapYourMap.end(), if they are equal you have passed the last element and trying to access data through the iterator will cause an exception.
Example for std::vector (if vecInt is a vector< int >):
vector<int>::iterator it = vecInt.begind();
if (it == vecInt.end()) return; // vector is empty
do { // runs through elememts until out of bound, useful for searching
i++
while (it != vecInt.end());

Filing a vector outside of a function in a class

Fairly simple question here, whats the best way to fill a vector outside of a function in a class .cpp file? currently i'm attempting the following which is not working:
std::vector<Player> midfielder(8);
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
To provide context, 'Midfielder' is a class that inherits from the 'Player' class.
TeamManagment.h
#ifndef TEAMMANAGEMENT_H
#define TEAMMANAGEMENT_H
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include <string>
class TeamManagement
{
public:
TeamManagement();
void Display_Players();
};
#endif // TEAMMANAGEMENT_H
TeamManagement.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include "TeamManagement.h"
using namespace std;
TeamManagement::TeamManagement()
{
}
std::vector<Player> midfielder(8);
//errors start occurring on line below: 'midfielder' does not name a type
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
//errors stop occurring here
void TeamManagement::Display_Players(){
cout<<"Position Name ID"<<endl;
for (int i=1;i<8;i++)
{
cout<<midfielder[i].Player_Details()<<" "<<midfielder[i].Get_player_id()<<endl;
}
}
The first problem is that you cannot perform assignment like that outside of a function. You must use construction or initialization.
With C++98 you cannot populate/initialize a vector outside of a function.
With C++11/14 you can populate one using initializer syntax:
#include <iostream>
#include <vector>
struct Thing {
int m_i, m_j;
Thing(int i, int j) : m_i(i), m_j(j) {}
};
std::vector<Thing> things {
{ 1, 2 }, { 2, 3 }
};
int main() {
std::cout << "things[0].m_j = " << things[0].m_j << '\n';
}
But std::vector won't like you trying to put "Midfielder"s into a vector of Player. Lets use an SSCCE to reconstruct the damage you're doing:
#include <iostream>
struct Base {
int i;
};
struct Derived : public Base {
int j;
};
int main() {
std::cout << "Base size = " << sizeof(Base) << '\n';
std::cout << "Derived size = " << sizeof(Derived) << '\n';
}
This tells us that Base and Derived have a different size. But you're trying to put these two objects into the same container because they're related. Round peg and square peg are related... They won't fit into the same hole, and this is the problem we have now.
The vector creates space in memory for your elements based on the type you supply, and then it requires you to pass it exactly that type to populate those spaces with, or a type that has a conversion mechanism to the storage type.
If you want to have a container of different types, you'll need to use pointers, but then you're going to run into the problem that what you get back will be a pointer to the base type and you will need to provide yourself with a way to distinguish different player types.
See Store derived class objects in base class variables for the C++98 approach. In modern C++ (11 and 14) you should use smart pointers, e.g.
std::vector<std::unique_ptr<Base>>
std::vector<std::shared_ptr<Base>>
Presumably default constructing a Midfielder doesn't make a lot of sense, so you can reserve the memory, then emplace_back into the vector.
std::vector<Player> midfielder {};
midfielder.reserve(8);
midfielder.emplace_back("Default ",0,"Midfielder");
midfielder.emplace_back("David Armitage ",1,"Midfielder");
midfielder.emplace_back("Tom Rockliff ",2,"Midfielder");
midfielder.emplace_back("Gary Ablett ",3,"Midfielder");
midfielder.emplace_back("Dyson Heppel ",4,"Midfielder");
midfielder.emplace_back("Scott Pendlebury",5,"Midfielder");
midfielder.emplace_back("Michael Barlow ",6,"Midfielder");
midfielder.emplace_back("Jack Steven ",7,"Midfielder");
midfielder.at(0) = Midfielder("Default ",0,"Midfielder"); is a statement. You've put that and similar statements in (global) namespace scope. That's your bug. Only declarations may be in namespace scope. You must put your statements inside a function.
The error message stems from the fact that declarations which don't start with a keyword start with a type name. Since midfielder is not a keyword, the compiler expects it to be a type name but it isn't one, so you get the error.

Another way to refer members in a structure

Now, I am learning as to how to use structures properly in C++.
Is there another way to refer members in a structure.
As an example, below is my code.
I want to know if I can do something like test.b to refer name member in the structure.
Is there any incredible way to do so?
#include <iostream>
using namespace std;
struct A
{
string name = "Test";
};
int main()
{
A test;
string b = "name";
cout << test.name;
return 0;
}
If you don't need to use a string to reference the member then the way to do this is called "pointer to member":
struct A
{
int name;
int value;
};
main()
{
int A::* b = &A::name; // assign "name" to the variable called b
struct A test = {1,2}; // make a structure and fill it in
return test.*b; // use the variable called b to reference test.name
}
If you do need to refennce the items with a string the other way mentioned in the contents is to use a map. That can be useful if all your members are the same type.
#include <iostream>
#include <map>
main()
{
std::map<std::string,int> test; // make something that can be keyed by a string
test["name"]=1; // put something called "name" in the map with a value of 1
test["value"]=2; // put something called "value" in the map with a value of 2
std::cout << test["name"] << std::endl;
return 0;
}
What you are referring to is called Reflection (function/attribute access by name). C++ by default doesn't have reflection. So probably you need to look for libraries/frameworks for that. Google "C++ Reflection" for that. Boost is one of the solution out there for C++ reflection/serialization.