Saving struct data to a map in C++ - c++

How would I add data to map containing an int key and a value that is a struct without first creating and defining an actual object with the struct type? Basically I have:
struct myStruct { string name2; int aCnt; std::list<string> theItems; };
// Now I define a map
std::map<string, myStruct> myMap;
// Now I want to add items to myMap.
mymap["ONE"] = {"TEN", 3, {"p1","p2","p3"}}; // But this doesn't seem to work
// I know I could do something like
myStruct myst;
myst.name2 = "TEN";
myst.aCnt = 3;
...blah blah
mymap["ONE"] = myst;
// But I don't want to have to write all of those lines especially because
// this is being done as an initialization of the map.
Thanks!

If you are using C++11, this code is already working:
#include <iostream>
#include <map>
#include <string>
#include <list>
using namespace std;
struct myStruct { string name2; int aCnt; std::list<string> theItems; };
int main()
{
// Now I define a map
std::map<string, myStruct> myMap;
// Now I want to add items to myMap.
myMap["ONE"] = {"TEN", 3, {"p1","p2","p3"}}; // But this doesn't seem to work
return 0;
}
And compile:
burgos#germany:~/test$ g++ struct.cpp -o struct -std=c++11
burgos#germany:~/test$
If you don't then you're out of luck, but all major compilers should support c++11 initialization - make sure you get the latest version.

Related

How to most concisely initialize std::map using an initializer list that includes a constructor call for the mapped_type

The vector constructor calls in the statement below construct vectors with 50 elements of identical values in each vector as values in the sviMap. The statement repeats vector<int> three times. Is there a more concise way to achieve this overall initialization of the sviMap where vector<int> appears only once in the statement?
map<string, vector<int>> sviMap { {"Leo", vector<int>(50, 101)} , {"Brad", vector<int>(50, 201)} };
Strictly speaking, no. You need to have template specialization and two instances of the vector.
But if you need to have "this text once", this workaround could work for you:
using vi = vector<int>;
map<string, vi> sviMap{ {"Leo", vi(50, 101)} , {"Brad", vi(50, 201)} };
Formally, this is not "the statement", but two statements, but the vector appears only once. If your goal is to have one point for changes, this could work.
I wanted to correct my mistake, so here's another solution.
And this one will result in vectors of the correct length.
I just used inheritance to create a vector type with a constructor that has the desired behavior, so you can then use initializer lists without extra specifics
#include <cassert>
#include <map>
#include <vector>
#include <string>
template<typename type_t>
class my_vector :
public std::vector<type_t>
{
public:
my_vector() = default;
my_vector(const size_t size, const type_t value) :
std::vector<type_t>(size, value)
{
}
};
int main()
{
std::map<std::string, my_vector<int>> sviMap{ { "Leo", {50, 101}}, { "Brad", {50, 201}} };
auto vec = sviMap["Leo"];
auto value = vec[23];
}
You can do it like this, just use nested initializers
#include <map>
#include <vector>
#include <string>
int main()
{
std::map<std::string, std::vector<int>> sviMap
{
{"Leo", {50, 101}},
{"Brad", {50, 201}}
};
auto vec = sviMap["Leo"];
}

How to copy elements from std::list to an array of struct?

I need to copy the contents of a std::list into an array, wherein the array is struct of array. Below is the code implementation of it.
#include <iostream>
#include <string>
using namespace std;
typedef struct
{
int height;
int width;
int length;
}dimensions;
GetDimensions(list<std::string>, *int); // Function that copies the content of list to array passed as second parameter
int main()
{
dimensions cuboid[10];
int plane[10];
list<std::string> planeList = GetList();//Function that returns list of elements
list<std::string> dimensionList = GetList();
GetDimensions(planeList,&plane);//This is fine, as it is a simple array
GetDimensions(dimensionList,&cuboid.height);//Trouble in implementation of this usecase, for cuboid.height, cuboid.width and cuboid.height.
return 0;
}
GetDimensions(list<std::string>dimensionList, int* dimensionParams)
{
int i=0;
for(list<std::string>::iterator it = dimensionList.begin(); it != dimensionList.end(); ++it)
{
dimensionParams[i] = stoi(*it);
i++;
}
}
Here, I need GetDimensions() function to copy the list (passed as first parameter) to array (second parameter). The implemented function works well for simple array plane. But how to pass the array of struct as parameter to the function ?
I will be getting the std::list as cuboid.height, cuboid.width and cuboid.length. So the function has to copy the contents of list from cuboid[0].height to cuboid[i].height respectively. Is there any specific function to copy the content directly?
Use std::array 's instead. Then your problem can be reduced to passing two different types of arrays to a single function.
This can be solved
either by good old function overloads
or in c++17 function template with
if-constexpr.
Following is an example code with templated function with if-constexpr (See live online)
#include <iostream>
#include <string>
#include <list>
#include <array>
#include <type_traits> // std::is_same_v
struct dimensions // no need to typedef here
{
int height;
int width;
int length;
};
template<typename T>
void GetDimensions(const list<std::string>& dimensionList, T& dimensionParams)
^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //---> pass list by const-ref as the values are non-modifying
{
int i{0};
if constexpr (std::is_same_v<std::array<int, 10>, T>)
{
for(const std::string& str: dimensionList) dimensionParams[i++] = std::stoi(str);
}
else
{
for(const std::string& str: dimensionList) dimensionParams[i++].height = std::stoi(str);
}
}
int main()
{
std::array<dimensions, 10> cuboid; // use std::array instead of VLA
std::array<int, 10> plane;
std::list<std::string> planeList{"1", "2"}; // some list
std::list<std::string> dimensionList{"1", "2"};
GetDimensions(planeList, plane);
GetDimensions(dimensionList, cuboid);
return 0;
}
Also note that:
You have not specified the return type of GetDimensions function.
You probably want to return void there.
in C++ you do not need to use typedef alias for struct { ... }.
last but not least, do not practice with using namespace std;
You can do this with boost::transform_iterator.
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
struct dimensions {
int height;
int width;
int length;
};
template <typename OutputIt>
void GetDimensions(std::list<std::string> dimensionList, OutputIt dimensionParams)
{
// N.b. taking the address of a standard library function is undefined, so wrap in a lambda
auto stoi = [](std::string s){ return std::stoi(s); };
std::copy(boost::make_transform_iterator(dimensionList.begin(), stoi),
boost::make_transform_iterator(dimensionList.end(), stoi),
dimensionParams);
}
int main() {
dimensions cuboid[10];
int plane[10];
std::list<std::string> planeList = GetList();
std::list<std::string> heightList = GetList();
std::list<std::string> widthList = GetList();
std::list<std::string> lengthList = GetList();
GetDimensions(planeList, plane);
GetDimensions(heightList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::height)));
GetDimensions(widthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::width)));
GetDimensions(lengthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::length)));
return 0;
}

How to create a Primary Key in a dynamic matrix

I don't know how to create a dynamic std::vector in which I want to allocate Usernames as PrimaryKeys, and each username would be a pointer to another dynamic vector containing structs that have the following information:
struct message{
int id;
char *msg;
const string time;
};
I attach an illustrative image in order to make it more clear:
Where the username vector is the Primary Key pointing to a vector of structs previously mentioned.
How could I define it?
Instead of using a vector of usernames I preferred to use map this will guarantee that the username remains unique.
#include <map>
#include <vector>
#include <string>
#include <iostream>
struct message{
int id;
char *msg;
const std::string time;
};
int main()
{
std::map<std::string,std::vector<message *> > data;
message message1,message2;
message1.id = 1;
message1.msg = "Hi";
message2.id = 2;
message2.msg = "Hello";
std::vector<message *> messages;
messages.push_back(&message1);
messages.push_back(&message2);
data["smith"] = messages;
std::cout << (data["smith"]).at(0)->msg << std::endl;
}

Cannot declare array of strings as class member

I could not declare an array of strings in my class. Below my class definition:
class myclass{
public:
int ima,imb,imc;
string luci_semaf[2]={"Rosso","Giallo","Verde"};
};
and my main file
#include <iostream>
#include <fstream>
#include "string.h"
#include <string>
using namespace std;
#include "mylib.h"
int main() {
return 0;
}
Why do I get the following warnings / error?
You have two problems: The first is that you can't initialize the array inline like that, you have to use a constructor initializer list. The second problem is that you attempt to initialize an array of two elements with three elements.
To initialize it do e.g.
class myclass{
public:
int ima,imb,imc;
std::array<std::string, 3> luci_semaf;
// Without C++11 support needed for `std::array`, use
// std::string luci_semaf[3];
// If the size might change during runtime use `std::vector` instead
myclass()
: ima(0), imb(0), imc(0), luci_semaf{{"Rosso","Giallo","Verde"}}
{}
};
You can not initialize data member.
You can write like this:
class myclass{
public:
myclass() {
luci_semaf[0] = "Rosso";
luci_semaf[1] = "Giallo";
luci_semaf[2] = "Verde";
}
private:
int ima,imb,imc;
string luci_semaf[3];
};
You can assign the values of the array in the Сonstructor
You're declaring an array of size 2 but providing 3 strings!
Try storing the elements in vector of strings, in c++ vectors are used more often.
class myclass{
public:
int ima,imb,imc;
std::vector<std::string> strings;
myclass() {
strings.push_back("blabla");
}
};

C++ Map of string and member function pointer

Hey so I am making a map with string as the key and a member function pointer as the value. I can't seem to figure out how to add to the map, this doesn't seem to be working.
#include <iostream>
#include <map>
using namespace std;
typedef string(Test::*myFunc)(string);
typedef map<string, myFunc> MyMap;
class Test
{
private:
MyMap myMap;
public:
Test(void);
string TestFunc(string input);
};
#include "Test.h"
Test::Test(void)
{
myMap.insert("test", &TestFunc);
myMap["test"] = &TestFunc;
}
string Test::TestFunc(string input)
{
}
See std::map::insert and std::map for value_type
myMap.insert(std::map<std::string, myFunc>::value_type("test", &Test::TestFunc));
and for operator[]
myMap["test"] = &Test::TestFunc;
You cannot use a pointer to member function without an object. You can use the pointer to member function with an object of type Test
Test t;
myFunc f = myMap["test"];
std::string s = (t.*f)("Hello, world!");
or with a pointer to type Test
Test *p = new Test();
myFunc f = myMap["test"];
std::string s = (p->*f)("Hello, world!");
See also C++ FAQ - Pointers to member functions