C++0x initializer list example - c++

I would like to see how this example of existing code would be able to take advantage of the C++0x initializer list feature.
Example0:
#include <vector>
#include <string>
struct Ask {
std::string prompt;
Ask(std::string a_prompt):prompt(a_prompt){}
};
struct AskString : public Ask{
int min;
int max;
AskString(std::string a_prompt, int a_min, int a_max):
Ask(a_prompt), min(a_min), max(a_max){}
};
int main()
{
std::vector<Ask*> ui;
ui.push_back(new AskString("Enter your name: ", 3, 25));
ui.push_back(new AskString("Enter your city: ", 2, 25));
ui.push_back(new Ask("Enter your age: "));
}
Would it support something like this:
Example1:
std::vector<Ask*> ui ={
AskString("Enter your name: ", 3, 25),
AskString("Enter your city: ", 2, 25),
Ask("Enter your age: ")
};
Or must it have literals like this?:
Example2:
std::vector<Ask*> ui ={
{"Enter your name: ", 3, 25},
{"Enter your city: ", 2, 25},
{"Enter your age: "}
};
If so how would the difference between AskString and Ask be handled?

You last examples wouldn't be allowed as you ask for pointers but try to provide local temporary objects instead.
std::vector<Ask*> ui ={
new AskString{"Enter your name: ", 3, 25},
new AskString{"Enter your city: ", 2, 25},
new Ask{"Enter your age: "}
};
That would be allowed and there would be no type ambiguity.
That would be right too :
std::vector<Ask*> ui ={
new AskString("Enter your name: ", 3, 25),
new AskString("Enter your city: ", 2, 25),
new Ask("Enter your age: ")
};
And your example is more like :
std::vector<Ask> ui ={ // not pointers
{"Enter your name: "},
{"Enter your city: "},
{"Enter your age: "}
};
std::vector<AskString> uiString ={ // not pointers
{"Enter your name: ", 3, 25},
{"Enter your city: ", 2, 25},
{"Enter your age: ", 7, 42}
};
and again there would be no ambiguity on the types.

A c++ initializer list is homogenous, meaning it must have all the same type, so example #2 is out. If you used new in example 1, it would work.

Related

Initialize the array of struct in c++11

I am facing a problem in initializing an array of struct. Below is the code:
#include <iostream>
#include <array>
#include <string>
#define NUM_ELEMENT 5
struct Person
{
std::string m_name;
int m_age = 0;
Person() = default;
Person(std::string name, int age)
: m_name(name), m_age(age) {}
};
typedef std::array<Person, NUM_ELEMENT> PersonList;
class Detail
{
public:
void InitializePerson();
private:
PersonList personList;
};
void Detail::InitializePerson()
{
personList{ // <------ Getting Error here..
Person("abc", 10),
Person("cde", 20),
Person("pqr", 30),
Person("xyz", 40),
Person("apple", 50),
};
}
int main()
{
Detail detail;
detail.InitializePerson();
return 0;
}
Though, I know I can use the std::vector with push_back but I want to achive this through the static array as it elements are fixed. I want to initialize the array with above class Detail member and since the data can be random, so not able to do in for loop by personList[0] = Person{};
You are trying to initialize personList which can only be done at construction - but personList is already constructed so that doesn't work. You should be assigning instead:
personList = {
Person("abc", 10),
Person("cde", 20),
Person("pqr", 30),
Person("xyz", 40),
Person("apple", 50),
};
alternatively:
personList = {{
{"abc", 10},
{"cde", 20},
{"pqr", 30},
{"xyz", 40},
{"apple", 50},
}};
If you want it initialized, you could do that in a Detail constructor:
class Detail {
public:
Detail() :
personList{{
{"abc", 10},
{"cde", 20},
{"pqr", 30},
{"xyz", 40},
{"apple", 50},
}}
{}
private:
PersonList personList;
};
Seems you are missing = operator
personList = {
Person("abc", 10),
Person("cde", 20),
Person("pqr", 30),
Person("xyz", 40),
Person("apple", 50),
};
This seems to do
personList = {{
{ "abc", 10 },
{ "cde", 20 },
{ "pqr", 30 },
{ "xyz", 40 },
{ "apple", 50 },
}};
See this answer.

How to add an if statement to a struct initialization

I'm trying to add an if statement in a nested struct, and whenever I try to build I get: syntax error: unexpected if, expecting expression.
I've found a simple code that shows what i'm trying to do:
package main
import "fmt"
type Salary struct {
Basic, HRA, TA float64
}
type Employee struct {
FirstName, LastName, Email string
Age int
MonthlySalary []Salary
}
func main() {
e := Employee{
FirstName: "Mark",
LastName: "Jones",
Email: "mark#gmail.com",
Age: 25,
MonthlySalary: []Salary{
Salary{
Basic: 15000.00,
HRA: 5000.00,
TA: 2000.00,
},
Salary{ //i want to add a condition "if true" then add this salary struct
Basic: 16000.00,
HRA: 5000.00,
TA: 2100.00,
}, // till here
Salary{
Basic: 17000.00,
HRA: 5000.00,
TA: 2200.00,
},
},
}
And I found that this might be done through preprocessor, which I'm totally clueless about.
Please note that the struct is imported from another package on my original code and I can't change the way it's declared and used.
You cannot put logic inline in a struct. You must do it outside of the variable declaration. But this is easy. For example:
func main() {
// Initialize a slice of `salaries` with the first
// value you know you need.
salaries := []Salary{
{
Basic: 15000.00,
HRA: 5000.00,
TA: 2000.00,
},
}
if /* your condition */ {
// conditionally add the second one
salaries = append(salaries, Salary{
Basic: 16000.00,
HRA: 5000.00,
TA: 2100.00,
})
}
// And finally add the last one
salaries = append(salaries, Salary{
Basic: 17000.00,
HRA: 5000.00,
TA: 2200.00,
})
e := Employee{
FirstName: "Mark",
LastName: "Jones",
Email: "mark#gmail.com",
Age: 25,
// And here include them in the variable declaration
MonthlySalary: salaries,
}

Iterate over a list of objects

In JavaScript I might iterate over a set of objects containing data, like this:
const components = [
{
id: 1,
pin: "A0",
name: "light"
},
{
id: 2,
pin: "A1",
name: "sound"
},
{
id: 1,
pin: "A0",
name: "heat"
},
]
for (const component of components) {
const value = analogRead(component.pin);
console.log(`${component.name}:value`)
}
I often have a need to use code like this on the Arduino, but I'm not sure how I'd go about it.
NOTE: I'm not looking for an exact translation of this into C++; I want to know what the standard pattern is for achieving this is when using Arduino.
You can use C structure. To do so you need to declare a structure first describing your object type.
struct component
{
int id;
char pin[10];
char name[50];
};
component components[] = {
{
1,
"A0",
"light"},
{
2,
"A1",
"sound"},
{
1,
"A0",
"heat"}
};
int main ()
{
int len = sizeof(components)/sizeof(components[0]);
for (int i=0 ; i<len ; i++)
{
printf("{ id: %d , pin: \"%s\" , name: \"%s\" }\n",components[i].id, components[i].pin, components[i].name);
}
return 0;
}
Output:
{ id: 1 , pin: "A0" , name: "light" }
{ id: 2 , pin: "A1" , name: "sound" }
{ id: 1 , pin: "A0" , name: "heat" }
If you're using modern C++ (11 or newer, which I understand arduino support), and your data is stored in an array you can simply do the following:
int values[5] = { 16, 2, 77, 40, 12071 }
for(auto const& value: values) {
// Do stuff
}

cpp too many initializers - struct in struct in array

I'm new to cpp since a few days and struggling with the following definition:
struct menuItem {
char* name;
int value;
};
struct topMenu {
int menuIcon;
char* Name;
menuItem item[];
};
topMenu menuRoot[] = {
{ 0, "File",
{"Open ...", 1},
{"New ...", 4},
{"Close", 1},
{"Exit", 3}
},
{ 0, "Edit",
{"Cut ", 3},
{"Copy", 8},
{"Paste", 2},
{"Find", 1},
{"Replace", 6}
},
{ 0, "Help",
{"Help", 7},
{"About", 9},
{"Update ..", 9}
}
};
I receive the error
33:1: error: too many initializers for 'menuItem [0]'
33:1: error: too many initializers for 'topMenu'
33:1: error: too many initializers for 'menuItem [0]'
33:1: error: too many initializers for 'topMenu'
33:1: error: too many initializers for 'menuItem [0]'
33:1: error: too many initializers for 'topMenu'
Sorry, i'm a little bit stuck ... maybe its just to late :)
Thanks in advance.
First, wrap the menuItem item[] array in {} because currently it thinks there are many arrays rather than just one.
Next, change the char * to const char * as was mentioned.
Now for the flexible amount of menuItem structs, use a vector rather than an array.
#include <vector>
struct menuItem {
const char *name;
int value;
};
struct topMenu {
int menuIcon;
const char *Name;
std::vector<menuItem> item;
};
topMenu menuRoot[] = {
{ 0, "File", {
{"Open ...", 1},
{"Open ...", 1},
{"Open ...", 1},
{"Open ...", 1},
}
},
{ 0, "Help", {
{"Open ...", 1},
{"Open ...", 1},
{"Open ...", 1}, }
}
};

Order repeating entries by sum of one field with distinct of another

I looked around and couldn't find a good answer for this, and I'm completely new to Mongo so here is the thing if someone can help.
I have a collection in mongo which holds user related data, in this manner:
{user: 4, rate: 2, location: 1}
{user: 5, rate: 4, location: 1}
{user: 6, rate: 3, location: 1}
{user: 5, rate: 2, location: 1}
{user: 4, rate: 5, location: 1}
...
{user: x, rate: y, location: z}
Now I need a query that will return me all the users on certain location (here is 1 but can be anything) together with final sum of all the rates for that user, and all that ordered by that same sum of rates (hope this makes sense). So something like this :
{4: 7, 5: 6, 6: 3} -> {user: sum(rate)} - ordered by sum(rate)
Any ideas guys?
I will be doing this in mongoengine for Django so if anyone knows how to do this there cool, but if not I'll just do a raw query so any help is good.
Thanks a bunch!
The MongoDB feature you are looking for is the Aggregation Framework.
Here is an example query in the mongo shell:
db.collection.aggregate(
// Find matching documents (can take advantage of suitable index if present)
{ $match: {
location: 1
}},
// Add up rates by user
{ $group: {
_id: "$user",
rates: { $sum: "$rate" }
}},
// Order by total rates (ascending)
{ $sort: { rates: 1 }}
)
Sample results given your data in the question:
[
{
"_id" : 6,
"rates" : 3
},
{
"_id" : 5,
"rates" : 6
},
{
"_id" : 4,
"rates" : 7
}
]
As an optional step in the aggregation, you might want to use $project to rename the grouped _id field to user.