How do I initialize a map with initializer list - c++11

I'm stuck with a map initialization problem.
I want a table to access all the directions of my tetris blocks.
I have tried a lot of methods to initialize it, but it seems too complex to be initialized.
This is the error info this time:
错误 C2440 “初始化”: 无法从“initializer list”转换为“std::map,std::allocator<_Ty>>,std::allocator>>>,std::less<_Kty>,std::allocator>,std::allocator>>>>>>” WinApp c:\codes\learning\winapp\tetris.cpp 44
I wonder how to initialize this table.
in my
block
class:
typedef std::map<shapes, std::vector < std::vector<std::pair<int, int> > > > proj;
static proj dirs ;
in the .cpp file:
block::proj block::dirs =
{
{ 6,{ { TL, TC, MR },{ TC, ML, BL } } },
{ 4,{ { TR, TC, ML },{ TC, MR, BR } } },
{ 5,{ { ML, MR, BC },{ TC, MR, BC },{ TC, ML, MR },{ TC, ML, BC } } },
{ 3,{ { TL, TC, ML } } },
{ 2,{ { { ML, BL, MR },{ TC, BC, BR },{ TR, ML, MR },{ TL, TC, BC } } } },
{ 1,{ { ML, BR, MR },{ TR, TC, BC },{ TR, TC, BC },{ TL, MR, ML },{ TC, BC, BL } } },
{ 0,{ { ML, MR,{ 2,0 },{ TC, BC,{ 0,2 } } } } } // sticks out
};
I defined the pairs as const vars for short.
const std::pair<int, int> TL{ -1,-1 }; /* top left */
const std::pair<int, int> TC{ 0,-1 }; /* top center */
const std::pair<int, int> TR{ 1,-1 }; /* top right */
const std::pair<int, int> ML{ -1,0 }; /* middle left */
const std::pair<int, int> MR{ 1,0 }; /* middle right */
const std::pair<int, int> BL{ -1,1 }; /* bottom left */
const std::pair<int, int> BC{ 0,1 }; /* bottom center */
const std::pair<int, int> BR{ 1,1 }; /* bottom right */

Looks like misplaced braces in the last line of dirs declaration. Try to replace
{ 0,{ { ML, MR,{ 2,0 },{ TC, BC,{ 0,2 } } } } }
with
{ 0,{ { ML, MR,{ 2,0 } },{ TC, BC,{ 0,2 } } } }

Related

c++ export an array of struct

Hello i'v the following function that exports a single instance of a struct :
struct UserIdentity
{
std::string name;
int id;
};
std::map<std::string, int> g_UserIdentities = { { "Bob", 100 }, { "Jone", 101 },
{ "Alice", 102 }, { "Doe", 103 } };
/*
* Will be used in a DLL that will export UserIdentity struct
* OUT _UserIdentity
*/
void Ui_export(UserIdentity *_UserIdentity)
{
for (auto& t : g_UserIdentities)
{
_UserIdentity->name = t.first;
_UserIdentity->id = t.second;
}
}
So please how could i export an array of _UserIdentity instead of a single instance in my function
void Ui_export(UserIdentity *_UserIdentity)
thank you .

How to pass a compile time array with var length to a constructor?

I have the following code:
struct MyArrayEntry
{
int type;
int id;
};
template<size_t arraySize>
struct MyArray
{
template<typename T, typename... Types>
MyArray(T t, Types... ts) : data{ { t, ts... } } {}
int dataSize = arraySize;
MyArrayEntry data[arraySize];
};
void Blah()
{
static MyArray<3> kTest
(
{ 1, 4 },
{ 2, 5 },
{ 3, 6 }
);
}
But this fails to build with:
error C2661: 'MyArray<3>::MyArray': no overloaded function takes 3
arguments
What am I doing wrong here?
With the imformation you provide, I would suggest using a std::initializer_list and an std::copy call:
template<size_t arraySize>
struct MyArray
{
const int dataSize = arraySize; // Could as well make it constant
MyArrayEntry data[arraySize];
MyArray(std::initializer_list<MyArrayEntry> elements)
{
std::copy(begin(elements), end(elements), std::begin(data));
}
};
Create as
MyArray<3> kTest({ { 1, 4 }, { 2, 5 }, { 3, 6 } });
Sure it's an extra pair of curly-brackets {}, but it will make your code simpler.

Iterate through multilevel boost tree

With my tree looking like this:
{
"Library":
{
"L_ID": "1",
"Book":
{
"B_ID": "1",
"Title": "Moby Dick"
},
"Book":
{
"B_ID": "2",
"Title": "Jurassic Park"
}
},
"Library":
{
"L_ID": "2",
"Book":
{
"B_ID": "1",
"Title": "Velocity"
},
"Book":
{
"B_ID": "2",
"Title": "Creeper"
}
}
}
What i am looking to do is iterate through the libraries. When i find the L_ID that i am looking for, iterate through the books until i find the B_ID i'm looking for. At that point, i'd like to access all the leaves in that section.
I.e. looking for library 2, book 1, title
Note: There's likely a better way than this.
boost::property_tree::ptree libraries = config_.get_child("Library");
for (const auto &lib : libraries)
{
if (lib.second.get<uint16_6>("L_ID") == 2)
{
//at this point, i know i'm the correct library...
boost::property_tree::ptree books = lib.get_child("Book");
for (const auto &book : books)
{
if (book.second.get<uint16_t>("B_ID") == 1)
{
std::string mybook = book.second.get<std::string>("Title");
}
}
}
I fail out as soon as i try looking into my first sub tree. What's going wrong here??
For starters, the "JSON" is wildly flawed. At least fix the missing quotes and commas:
{
"Library": {
"L_ID": "1",
"Book": {
"B_ID": "1",
"Title": "Moby Dick"
},
"Book": {
"B_ID": "2",
"Title": "Jurassic Park"
}
},
"Library": {
"L_ID": "2",
"Book": {
"B_ID": "1",
"Title": "Velocity"
},
"Book": {
"B_ID": "2",
"Title": "Creeper"
}
}
}
Next up, you seem to be confused. get_child("Library") gets the first child by that name, not a node containing child nodes called "Library" (that would be the root node, by the way).
May I suggest adding some abstraction, and perhaps some facilities to query by some names/properties:
int main() {
Config cfg;
{
std::ifstream ifs("input.txt");
read_json(ifs, cfg.data_);
}
std::cout << "Book title: " << cfg.library(2).book(1).title() << "\n";
}
As you can see, we assume a Config type that can find a library:
Library library(Id id) const {
for (const auto& lib : libraries())
if (lib.id() == id) return lib;
throw std::out_of_range("library");
}
What is libraries()? We'll delve into it deeper, but lets just look at it for a second:
auto libraries() const {
using namespace PtreeTools;
return data_ | named("Library") | having("L_ID") | as<Library>();
}
That magic should be read as "give me all nodes that are named Library, which have a L_ID property but wrap them in a Library object". Skipping on the detail for now, lets look at the Library object, which apparently knows about books():
struct Library {
ptree const& data_;
Id id() const { return data_.get<Id>("L_ID"); }
auto books() const {
using namespace PtreeTools;
return data_ | named("Book") | having("B_ID") | as<Book>();
}
Book book(Id id) const {
for (const auto& book : books())
if (book.id() == id) return book;
throw std::out_of_range("book");
}
};
We see the same pattern in books() and book(id) to find a specific item.
The Magic
The magic uses Boost Range adaptors and lurks in PtreeTools:
namespace PtreeTools {
namespace detail {
// ...
}
auto named(std::string const& name) {
return detail::filtered(detail::KeyName{name});
}
auto having(std::string const& name) {
return detail::filtered(detail::HaveProperty{name});
}
template <typename T>
auto as() {
return detail::transformed(detail::As<T>{});
}
}
That's deceptively simple, right. That's because we're standing on the shoulders of Boost Range:
namespace detail {
using boost::adaptors::filtered;
using boost::adaptors::transformed;
Next, we only define the predicates that know how to filter for a specific ptree node:
using Value = ptree::value_type;
struct KeyName {
std::string const _target;
bool operator()(Value const& v) const {
return v.first == _target;
}
};
struct HaveProperty {
std::string const _target;
bool operator()(Value const& v) const {
return v.second.get_optional<std::string>(_target).is_initialized();
}
};
And one transformation to project to our wrapper objects:
template <typename T>
struct As {
T operator()(Value const& v) const {
return T { v.second };
}
};
}
Full Live Demo
Live On Coliru
#include <boost/property_tree/json_parser.hpp>
#include <boost/range/adaptors.hpp>
using boost::property_tree::ptree;
namespace PtreeTools {
namespace detail {
using boost::adaptors::filtered;
using boost::adaptors::transformed;
using Value = ptree::value_type;
struct KeyName {
std::string const _target;
bool operator()(Value const& v) const {
return v.first == _target;
}
};
struct HaveProperty {
std::string const _target;
bool operator()(Value const& v) const {
return v.second.get_optional<std::string>(_target).is_initialized();
}
};
template <typename T>
struct As {
T operator()(Value const& v) const {
return T { v.second };
}
};
}
auto named(std::string const& name) {
return detail::filtered(detail::KeyName{name});
}
auto having(std::string const& name) {
return detail::filtered(detail::HaveProperty{name});
}
template <typename T>
auto as() {
return detail::transformed(detail::As<T>{});
}
}
struct Config {
ptree data_;
using Id = uint16_t;
struct Book {
ptree const& data_;
Id id() const { return data_.get<Id>("B_ID"); }
std::string title() const { return data_.get<std::string>("Title"); }
};
struct Library {
ptree const& data_;
Id id() const { return data_.get<Id>("L_ID"); }
auto books() const {
using namespace PtreeTools;
return data_ | named("Book") | having("B_ID") | as<Book>();
}
Book book(Id id) const {
for (const auto& book : books())
if (book.id() == id) return book;
throw std::out_of_range("book");
}
};
auto libraries() const {
using namespace PtreeTools;
return data_ | named("Library") | having("L_ID") | as<Library>();
}
Library library(Id id) const {
for (const auto& lib : libraries())
if (lib.id() == id) return lib;
throw std::out_of_range("library");
}
};
#include <iostream>
int main() {
Config cfg;
{
std::ifstream ifs("input.txt");
read_json(ifs, cfg.data_);
}
std::cout << "Book title: " << cfg.library(2).book(1).title() << "\n";
}
Prints:
Book title: Velocity
#Sehe fixed your JSON to be syntactically correct, but I think it would make sense to go a bit further than that. Given the data you're representing, it would make a great deal more sense to have an array of libraries, each of which contains an array of books, giving data something like this:
{
"Libraries": [
{
"L_ID": 1,
"Books": [
{
"B_ID": 1,
"Title": "Moby Dick"
},
{
"B_ID": 2,
"Title": "Jurassic Park"
}
]
},
{
"L_ID": 2,
"Books": [
{
"B_ID": 1,
"Title": "Velocity"
},
{
"B_ID": 2,
"Title": "Creeper"
}
]
}
]
}
Then, if at all possible, I'd choose a library that's actually suited to the job at hand. Boost property tree isn't really intended as a general-purpose JSON library. You can push it into that role if you really insist, but at least for what you've outlined in the question, it puts you through quite a bit of extra work to get what you want.
Personally, I'd probably use nlohmann's JSON library instead. Using it, we can proceed a little more directly to a solution. Basically, once it's parsed a JSON file, we can treat the result a great deal like we would normal collections from the standard library--we can use all the normal algorithms, range-based for loops, and so on. So, we can load a JSON file something like:
using json=nlohmann::json;
std::ifstream in("libraries.json");
json lib_data;
in >> lib_data;
Then we can look through the libraries for a particular ID number with code something like this:
for (auto const &lib : libs["Libraries"])
if (lib["L_ID"] == lib_num)
// we've found the library we want
Looking for a particular book is nearly identical:
for (auto const &book : lib["Books"])
if (book["B_ID"] == book_num)
// we've found the book we want
From there, printing out the title looks something like: std::cout << book["Title"];
Putting those together, we could end up with code something like this:
#include "json.hpp"
#include <fstream>
#include <iostream>
using json = nlohmann::json;
std::string find_title(json lib_data, int lib_num, int book_num) {
for (auto const &lib : lib_data["Libraries"])
if (lib["L_ID"] == lib_num)
for (auto const &book : lib["Books"])
if (book["B_ID"] == book_num)
return book["Title"];
return "";
}
int main() {
std::ifstream in("libraries.json");
json lib_data;
in >> lib_data;
std::cout << find_title(lib_data, 1, 2);
}
If you really want to convert each JSON object into a C++ object, you can do that fairly easily as well. It would look something like this:
namespace library_stuff {
struct Book {
int B_ID;
std::string title;
};
void from_json(json &j, Book &b) {
b.B_ID = j["B_ID"];
b.title = j["Title"];
}
}
So there are two points here: you must name the function from_json, and it must be defined in the same namespace as the struct/class it's associated with. With this bit of scaffolding in place, we can convert from JSON to struct with a simple assignment, something like this:
book b = lib_data["Libraries"][0]["Books"][1];
I'd consider it highly questionable whether that's really useful in this particular case though.

Extending std::vector<std::pair<...>> with own functionality

My C++11 is too weak to find a solution. I have lot of std::vector<std::pair<const char *, int>> variables in my project and therefore the code to check if an entry does exist repeats:
std::vector<std::pair<const char *, RunningProgramMode>> vProgramMode =
{
{ "server", RunningProgramModeServer },
{ "shell", RunningProgramModeShell },
{ "client", RunningProgramModeClient },
};
// the following code repeats for each variable
for ( auto const &it : vProgramMode )
{
if ( !strcmp(sParameter, it.first) )
{
programParameters->requestedProgramMode = it.second;
}
}
Of course I can write a function [which receives std::vector<std::pair<..>> as parameter] which iterates through the vector but I think it would be more elegant when I can extend the std::vector template with my find_member() function which checks with !strcmp(sParameter, it.first) if the vector has the requested entry and returns then .second value.
Something like this:
std::my_vector<std::pair<const char *, RunningProgramMode>> vProgramMode =
{
{ "server", RunningProgramModeServer },
{ "shell", RunningProgramModeShell },
{ "client", RunningProgramModeClient },
};
result = vProgramMode.find_member("shell");
For the moment there is no need to check if the value does exist. I want to keep the example simple and focus on the problem.
My solution:
template<typename T>
class MyVectorForPair
{
private:
std::vector<std::pair<const char *, T>> classObject;
public:
MyVectorForPair(std::vector<std::pair<const char *, T>> initVector)
{ classObject = initVector; }
auto find_member(const char * sMember, T defaultReturn) -> T;
};
template<typename T>
auto MyVectorForPair<T>::find_member(const char * sMember, T defaultReturn) -> T
{
for ( auto const &it : classObject )
{
if ( !strcmp(sMember, it.first) )
{
return it.second;
}
}
return defaultReturn;
}
I can use it then like this - now it is general:
MyVectorForPair<RunningProgramMode> vProgramMode
(
{
{ "server", RunningProgramModeServer },
{ "shell", RunningProgramModeShell },
{ "client", RunningProgramModeClient },
}
);
RunningProgramMode result;
result = vProgramMode.find_member(sParameter, RunningProgramModeNotSelected));

Visual C++ initliazing aggregates inline

In g++ I could do this:
struct s
{
int a, b;
};
void MyFunction(s) { }
int main()
{
MyFunction((s) { 0, 0 });
return 0;
}
In Visual Studio however, it doesn't work. is there any way to make it work or some alternative syntax without making a variable and initializing it (and without adding a constructor to the struct as it will make it non-aggregate and it wouldn't be able to initialize in aggregates)?
My C is a bit rusty, but didn't you have to use struct s unless you typedef it? Something like this:
struct s
{
int a, b;
};
void MyFunction(struct s) { }
int main()
{
MyFunction((struct s) { 0, 0 });
return 0;
}
or
typedef struct s
{
int a, b;
} s_t;
void MyFunction(s_t) { }
int main()
{
MyFunction((s_t) { 0, 0 });
return 0;
}

Resources