I made the following map to store data from a .log :
map<string,pair(int,map<string,int>)>.
I manage to store the data but not to retrieve it. What I do is:
cout<< "first string: "<< debut->first
<< " pair (first int): " << debut->second.first << endl;
(debut is a constant iterator of a map)
With that I get the first string and the int of the pair, but I don't know how to get the content of the map. I tried different syntaxes as debut->second.second->first or debut->second.second.first but of them work.
Does someone have an idea?
I don't know how to get the content of the map.
You can print out the content of the innermost map as shown below([DEMO]):
auto beg = debut->second.second.cbegin();
auto end = debut->second.second.cend();
while(beg!=end) //can also use for loop
{
std::cout<<beg->first<<" ";
std::cout<<beg->second<<std::endl;
++beg;
}
Here is a more complete example for printing the all the content of the maps, just for demonstration:
#include <iostream>
#include <map>
int main()
{
std::map<std::string,std::pair<int,std::map<std::string,int>>> m{ { "first", { 5, {{"a", 10}, {"b", 20}} }} ,
{ "second", { 6, {{"c", 100}, {"d", 200},{"e", 300} }}},
{ "third", { 7, {{"f", 400}} } }};
//////////////////////////////////////////////////////////////////
//PRINTING THE CONTENT OF THE MAP
auto debutBegin = m.cbegin(); //const iterator to beginning of outer map
auto debutEnd = m.cend(); //const iterator to end of outer map
while(debutBegin!=debutEnd)
{
auto beg = debutBegin->second.second.cbegin(); //const iterator to beginning of inner map
auto end = debutBegin->second.second.cend();//const iterator to end of inner map
std::cout<<debutBegin->first<<" ---- "<<debutBegin->second.first<<std::endl;
while(beg!=end)
{
std::cout<<beg->first<<" ";
std::cout<<beg->second<<std::endl;
++beg;
}
debutBegin++;
}
return 0;
}
Output
The output of the above program is:
first ---- 5
a 10
b 20
second ---- 6
c 100
d 200
e 300
third ---- 7
f 400
You probably need to iterate over the second map as well. Here's one way to do this:
map<string,pair<int,map<string,int>>> mp1;
map<string, int> mp2;
mp2["str2 inside mp1"] = 1;
mp1["str1 (key)"] = {2, mp2};
for(auto pair1 : mp1) {
cout << "First string: " << pair1.first << "\n"; // str1 (key)
cout << "First int: " << pair1.second.first << "\n"; // First int: 2
for(auto pair2 : pair1.second.second) {
cout << "Second string: " << pair2.first << "\n"; // Second string: str2 inside mp1
cout << "Second int: " << pair2.second << "\n"; // Second int: 1
}
}
However (as the comments suggest) this is a complicated approach, maybe you need to submit a new question explaining your usecase. My thought would be to seperate this into to seperate maps somehow.
I would recommend to:
split your printing into functions,
print one map at a time, and
use whatever number of variables/references you need to make your code clearer.
The code below is just an example that tries to follow that intent.
[Demo]
#include <iostream> // cout
#include <map>
#include <string>
#include <utility> // pair
using inner_map_t = std::map<std::string, int>;
using outer_map_t = std::map<std::string, std::pair<int, inner_map_t>>;
std::ostream& operator<<(std::ostream& os, const inner_map_t& m)
{
os << "\t{\n";
bool first_elem{true};
for (auto& [key, value] : m)
{
auto& second_string{ key };
auto& second_int{ value };
os
<< "\t\t" << (first_elem ? "" : ", ") << "second string: " << second_string << ", "
<< "second int: " << second_int << "\n";
first_elem = false;
}
os << "\t}\n";
return os;
}
std::ostream& operator<<(std::ostream& os, const outer_map_t& m)
{
os << "{\n";
bool first_elem{ true };
for (auto& [key, value] : m)
{
auto& first_string{ key };
auto& first_int{ value.first };
auto& inner_map{ value.second };
os
<< "\t" << (first_elem ? "" : ", ") << "first string: " << first_string << ", "
<< "first int: " << first_int << "\n"
<< inner_map;
first_elem = false;
}
os << "}\n";
return os;
}
int main()
{
const outer_map_t m{
{ "one", { 1, {{"uno", 10}, {"cien", 100}} } },
{ "two", { 2, {{"dos", 20}} } },
{ "three", { 3, {{"tres", 30}} } }
};
std::cout << m << "\n";
}
// Outputs:
//
// {
// first string: one, first int: 1
// {
// second string: cien, second int: 100
// , second string: uno, second int: 10
// }
// , first string: three, first int: 3
// {
// second string: tres, second int: 30
// }
// , first string: two, first int: 2
// {
// second string: dos, second int: 20
// }
// }
And another implementation, probably a bit neater.
[Demo]
#include <iostream> // cout
#include <map>
#include <string>
#include <utility> // pair
using inner_map_t = std::map<std::string, int>;
using pair_t = std::pair<int, inner_map_t>;
using outer_map_t = std::map<std::string, pair_t>;
template <typename T, typename U>
std::ostream& print_map(std::ostream& os, const std::map<T,U> m, size_t level_of_indent)
{
std::string indent(4*level_of_indent, ' ');
std::string next_indent(4*(level_of_indent + 1), ' ');
os << "{\n";
bool first{ true };
for (auto& [key, value] : m)
{
os << (first ? "" : ",\n") << next_indent << "'" << key << "' : " << value;
first = false;
}
os << "\n" << indent << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const inner_map_t& m) {
return print_map(os, m, 1);
}
std::ostream& operator<<(std::ostream& os, const pair_t& p) {
return os << "(" << p.first << ", " << p.second << ")";
}
std::ostream& operator<<(std::ostream& os, const outer_map_t& m) {
return print_map(os, m, 0);
}
int main()
{
const outer_map_t m{
{ "Alien", { 1, {{"speed", 90}, {"power", 90}} } },
{ "Jabba", { 2, {{"speed", 10}} } },
{ "T1000", { 3, {{"speed", 70}} } }
};
std::cout << m << "\n";
}
// Outputs:
//
// {
// 'Alien' : (1, {
// 'power' : 90,
// 'speed' : 90
// }),
// 'Jabba' : (2, {
// 'speed' : 10
// }),
// 'T1000' : (3, {
// 'speed' : 70
// })
// }
Related
How can I use a vector of variants as the key in unordered_map?
For example, I'd like to make the following code work.
using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;
std::unordered_map<VecVariantType, int, $some_hash_function$> m;
How do I implement $some_hash_function$?
I enjoy a good terrible idea...
I have no idea how or why you would use something like this for something other than a "I wonder if I can get this to compile and run" example.
#include <iostream>
#include <vector>
#include <unordered_map>
#include <variant>
using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;
struct Hasher
{
size_t operator()(const VecVariantType &v) const
{
size_t hash = 0;
for (auto &val : v)
{
hash ^= std::hash<VariantType>()(val);
}
return hash;
}
};
std::ostream& operator<<(std::ostream& out, std::pair<const VecVariantType, int> &p)
{
out << "key: { ";
bool needs_comma = false;
for (auto &var : p.first)
{
if (needs_comma)
{
out << ", ";
}
if (std::holds_alternative<int>(var))
{
out << "int: " << std::get<int>(var);
needs_comma = true;
}
if (std::holds_alternative<std::string>(var))
{
out << "string: " << std::get<std::string>(var);
needs_comma = true;
}
if (std::holds_alternative<unsigned int>(var))
{
out << "uint: " << std::get<unsigned int>(var);
needs_comma = true;
}
}
out << " }, value: " << p.second;
return out;
}
void lookup(const VecVariantType &var, std::unordered_map<VecVariantType, int, Hasher> &m)
{
std::cout << "Lookup ";
auto it = m.find(var);
if (it != m.end())
{
std::cout << "success - " << *it << "\n";
}
else
{
std::cout << "failure\n";
}
}
int main()
{
std::unordered_map<VecVariantType, int, Hasher> m;
auto one = VecVariantType { 1, "one", 1u };
auto two = VecVariantType { 2, "two", 2u };
auto three = VecVariantType { 3, "three", 3u };
auto nnn = VecVariantType { 1, "one", 1u, 2, "two", 2u, 3, "three", 3u };
m.emplace(one, 1);
m.emplace(two, 2);
m.emplace(three, 3);
m.emplace(nnn, 999);
std::cout << "Enumerating:\n";
for (auto& item : m)
{
std::cout << " " << item << "\n";
}
lookup(one, m);
lookup(two, m);
lookup(three, m);
lookup(nnn, m);
}
https://repl.it/repls/AmazingCrushingOpen64
I have a map which contains strings as keys; those string resemble wildcards.
A key can have a * at the end, which means that when a lookup is performed, a string that has this key as a prefix shall match this key.
How can I efficiently retrieve the closest matching entry in such a map?
I tried sorting the map entries in a custom way and then using lower_bound, but that sorting does not produce the correct result:
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
struct Compare {
bool operator()(const std::string& lhs, const std::string& rhs) const
{
if (lhs.size() < rhs.size()) {
return true;
}
if (lhs.size() > rhs.size()) {
return false;
}
bool isWildcardlhsAtEnd = (!lhs.empty() && lhs.back() == '*');
bool isWildcardrhsAtEnd = (!rhs.empty() && rhs.back() == '*');
if (isWildcardlhsAtEnd && isWildcardrhsAtEnd) {
return lhs < rhs;
}
auto lhSubString = lhs.substr(0, lhs.size() - 1);
auto rhsSubString = rhs.substr(0, rhs.size() - 1);
if (isWildcardlhsAtEnd || isWildcardrhsAtEnd) {
if (lhSubString == rhsSubString) {
return !isWildcardlhsAtEnd;
}
else {
return lhSubString < rhsSubString;
}
}
return lhs < rhs;
}
};
template <typename Map>
void lookup(const Map& map, const std::string& key, int expected)
{
auto it = map.lower_bound(key);
if (it != map.end()) {
std::cout << "found " << it->first << " for " << key << "; ";
std::cout << "expected: " << expected << " got: " << it->second << std::endl;
}
else {
std::cout << "did not find a match for " << key << std::endl;
}
}
int main()
{
std::map<std::string, int, Compare> map = {
{ "bar", 1 },
{ "bar*", 2 },
{ "foo1", 3 },
{ "bar1", 4 },
{ "bar1*", 5 },
{ "foo1*", 6 },
{ "bar12", 7 },
{ "bar12*", 8 },
{ "foo12", 9 },
{ "bar123", 10 },
{ "b*", 11 },
{ "f*", 12 },
{ "b", 13 },
{ "f", 14 }
};
std::cout << "sorted map \n------" << std::endl;
std::for_each(map.begin(), map.end(), [](const auto& e) { std::cout << e.first << std::endl; });
std::cout << "-------" << std::endl;
lookup(map, "foo1", 3);
lookup(map, "foo123", 6);
lookup(map, "foo", 12);
lookup(map, "bar1234", 8);
}
This produces the following output which demonstrates the incorrect lookup:
sorted map
------
b
f
b*
f*
bar
bar1
bar*
foo1
bar12
bar1*
foo12
foo1*
bar123
bar12*
-------
found foo1 for foo1; expected: 3 got: 3
did not find a match for foo123
found bar1 for foo; expected: 12 got: 4
did not find a match for bar1234
live example
I am also open to using another data structure if necessary.
If you separate the exact search and wildcard search, then the natural ordering works fine with strings. This code seems to produce the desired results (I think), and is efficient. The separate maps can be wrapped more conveniently of course.
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
template <typename Map>
void lookup(const Map& exact ,const Map& wilds, const std::string& key, int expected)
{
auto it = exact.find(key);
if (it == exact.end()) { // if not exact match
it = wilds.lower_bound(key); // do best match
it--;
}
std::cout << "found " << it->first << " for " << key << "; ";
std::cout << "expected: " << expected << " got: " << it->second << std::endl;
}
int main()
{
std::map<std::string, int> wilds = {
{ "bar*", 2 },
{ "bar1*", 5 },
{ "foo1*", 6 },
{ "bar12*", 8 },
{ "b*", 11 },
{ "f*", 12 }
};
std::map<std::string, int> exact = {
{ "bar", 1 },
{ "foo1", 3 },
{ "bar1", 4 },
{ "bar12", 7 },
{ "foo12", 9 },
{ "bar123", 10 },
{ "b", 13 },
{ "f", 14 }
};
lookup(exact , wilds, "foo1", 3);
lookup(exact , wilds,"foo123", 6);
lookup(exact , wilds,"foo", 12);
lookup(exact , wilds,"bar1234", 8);
}
I've a class withmap<string,vector<string>>.
I want to give a user a member function to receive the value for a key in different formats than std::vector(string):
vector(string),
string,
vector(int),
vector(float) and
bool
example:
bool x = (bool) myClass["dummy_boolean_type"]
x = myClass["dummy_boolean_type"].as<bool>
int y = (int) myClass["dummy_boolean_type"]
Can someone have an example what is the best way to achieve it ?
(without a use in Boost)
You cannot provide your class with any member function or functions
that will support the two constructions you want:
T x = myClassInstance["key"].as<T> // (1)
T x = (T) myClassInstance["key"] // (2)
In the case of (1), the immediate reason is simply that the construction is
not legal C++. So let's suppose it is replaced by:
T x = myClassInstance["key"].as<T>() // (1a)
But this doesn't help, and the reason is the same for both (1a) and (2):
The expression myClassInstance["key"] will have to evaluate to some object e or reference to such that is returned by:
myClass::operator[](std::string const &);
This e is the vector<string> to which key maps in your
map<string,vector<string> data member of myClass. It is not myClassInstance.
So what you are asking for are member functions of myClass that will support
the constructions:
T x = e.as<T> // (1b)
T x = (T) e // (2b)
where e is an std::vector<std::string>.
Clearly, nothing you can do in myClass can address your requirement. In
(1b) and (2b), myClass is nowhere to be seen.
Is there any template member function of std::vector<std::string>:
template<typename T>
T as() const;
that has the behaviour you want for (1b)?
Does std::vector<std::string> have any template member function:
template<typename T>
operator T() const;
that has the behaviour you want for (2b)?
No and No.
However...
You can implement an as template member function of myClass that
supports conversions such as you mention. Its signature - of course -
would be:
template<typename T>
T myClass::as(std::string const & key) const;
and you would invoke it like:
T x = myClassInstance.as<T>("key") // (1c)
I'll sketch an implemention that assumes we're content with the
conversions from std::vector<std::string> to:
std::string
std::vector<int>
bool
which will be enough to get you under way.
To convert an std::vector<std::string> vs to std::string I'll concatenate
the elements of vs.
To convert an std::vector<std::string> vs to std::vector<int> I'll convert each element of vs from a decimal numeral, if I can, to the
integer the numeral represents, and return a vector of those integers. Without
prejudice to other policies I'll throw an std::invalid_argument exception
when an element doesn't trim to a decimal numeral.
I am spoilt for choice as to what you might mean by converting an std::vector<std::string>
to bool, so I will arbitrarily say that vs is true if I can convert it
to a vector<int> of which any element is non-0 and is false if I can convert
it to a vector<int> in which all elements are 0.
The sketch:
#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
namespace detail {
template<typename T>
struct convert_to
{
static T from(std::vector<std::string> const & vs) {
static constexpr bool always_false = !std::is_same<T,T>::value;
static_assert(always_false,
"Calling `convert_to<T>::from` for unimplemented `T`");
return *(T*)nullptr;
}
};
template<>
std::string convert_to<std::string>::from(std::vector<std::string> const & vs)
{
std::string s;
for ( auto const & e : vs ) {
s += e;
}
return s;
}
template<>
std::vector<int>
convert_to<std::vector<int>>::from(std::vector<std::string> const & vs)
{
auto lamb = [](std::string const & s) {
std::size_t lastoff = s.find_last_not_of(" \t\f\v\n\r");
int i;
try {
std::size_t nlen;
i = std::stoi(s,&nlen);
if (nlen <= lastoff) {
throw std::invalid_argument("");
}
}
catch(std::invalid_argument const & e) {
throw std::invalid_argument(
"Cannot convert \"" + s + "\" to int");
}
return i;
};
std::vector<int> vi;
std::transform(vs.begin(),vs.end(),std::back_inserter(vi),lamb);
return vi;
}
template<>
bool convert_to<bool>::from(std::vector<std::string> const & vs)
{
auto vi = convert_to<std::vector<int>>::from(vs);
for (auto const & i : vi) {
if (i) {
return true;
}
}
return false;
}
} // namespace detail
struct myClass // Your class
{
// Whatever...
std::vector<std::string> & operator[](std::string const & key) {
return _map[key];
}
template<typename T>
T as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
// Whatever...
private:
std::map<std::string,std::vector<std::string>> _map;
};
The one take-away point here is the use of template<typename T>
detail::struct convert_to, with its solitary static member function:
T from(std::vector<std::string> const & vs)
which in the default instantiation will provoke a static_assert failure
reporting that no conversion to T from std::vector<std::string> has been
defined.
Then, for each type U to which you want a conversion, you have just to
write a specializing definition:
template<>
U convert_to<U>::from(std::vector<std::string> const & vs);
as you see fit, and the construction (1c) will use it as per:
template<typename T>
T myClass::as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
Here's an illustrative progam you can append to the sketch:
#include <iostream>
using namespace std;
template<typename T>
static void print_vec(std::vector<T> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << e << " ";
}
cout << "}\n";
}
static void print_vec(std::vector<std::string> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << '\"' << e << "\" ";
}
cout << "}\n";
}
int main()
{
myClass f;
f["int_vec"] = vector<string>{"0","1 "," 2"};
cout << "f[\"int_vec\"] = "; print_vec(f["int_vec"]);
f["true_vec"] = vector<string>{"0"," 1 ","0"};
cout << "f[\"true_vec\"] = "; print_vec(f["true_vec"]);
f["false_vec"] = vector<string>{"0"," 0","0 "};
cout << "f[\"false_vec\"] = "; print_vec(f["false_vec"]);
f["not_int_vec0"] = vector<string>{"0","1","2",""};
cout << "f[\"not_int_vec0\"] = "; print_vec(f["not_int_vec0"]);
f["not_int_vec1"] = vector<string>{"0","#","2",};
cout << "f[\"not_int_vec1\"] = "; print_vec(f["not_int_vec1"]);
f["not_int_vec2"] = vector<string>{"0"," 1$","2",};
cout << "f[\"not_int_vec2\"] = "; print_vec(f["not_int_vec2"]);
cout << "f.as<string>(\"int_vec\") = \""
<< f.as<string>("int_vec") << '\"' << endl;
cout << "f.as<string>(\"true_vec\") = \""
<< f.as<string>("true_vec") << '\"' << endl;
cout << "f.as<string>(\"false_vec\") = \""
<< f.as<string>("false_vec") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec0\") = \""
<< f.as<string>("not_int_vec0") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec1\") = \""
<< f.as<string>("not_int_vec1") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec2\") = \""
<< f.as<string>("not_int_vec2") << '\"' << endl;
vector<int> va = f.as<vector<int>>("int_vec");
cout << "f.as<vector<int>>(\"int_vec\") = ";
print_vec(f.as<vector<int>>("int_vec"));
cout << boolalpha << "f.as<bool>(\"true_vec\") = "
<< f.as<bool>("true_vec") << endl;
cout << boolalpha << "f.as<bool>(\"false_vec\") = "
<< f.as<bool>("false_vec") << endl;
try {
cout << "f.as<vector<int>>(\"not_int_vec0\")...";
auto b = f.as<vector<int>>("not_int_vec0");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec1\")...";
auto b = f.as<vector<int>>("not_int_vec1");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec2\")...";
auto b = f.as<vector<int>>("not_int_vec2");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
// char ch = f.as<char>("int_vec"); <- static_assert fails
return 0;
}
It outputs:
f["int_vec"] = { "0" "1 " " 2" }
f["true_vec"] = { "0" " 1 " "0" }
f["false_vec"] = { "0" " 0" "0 " }
f["not_int_vec0"] = { "0" "1" "2" "" }
f["not_int_vec1"] = { "0" "#" "2" }
f["not_int_vec2"] = { "0" " 1$" "2" }
f.as<string>("int_vec") = "01 2"
f.as<string>("true_vec") = "0 1 0"
f.as<string>("false_vec") = "0 00 "
f.as<string>("not_int_vec0") = "012"
f.as<string>("not_int_vec1") = "0#2"
f.as<string>("not_int_vec2") = "0 1$2"
f.as<vector<int>>("int_vec") = { 0 1 2 }
f.as<bool>("true_vec") = true
f.as<bool>("false_vec") = false
f.as<vector<int>>("not_int_vec0")...Cannot convert "" to int
f.as<vector<int>>("not_int_vec1")...Cannot convert "#" to int
f.as<vector<int>>("not_int_vec2")...Cannot convert " 1$" to int
(gcc 5.1, clang 3.6, C++11)
I am wondering if there is way that std::cout automatically will insert some predefined value between printed sequences.
For example:
std::cout << 2 << 3 << 33 << 45 << std::endl;
outputs
233345
and I would like it to output
2 3 33 45
and I know, that it's easy to:
std::cout << 2 << " " << 3 << " " << 33 << " " << 45 << std::endl;
But I'am wondering if there is a way to automate this, such as:
std::cout << set_some_separator(" ") << 2 << 3 << 33 << 45 << std::endl;
Anyone aware of something like this being possible?
Well, I got beaten to it. I'll post this anyway.
Edit : well, after reading Nim's answer, mine does achieve the exact syntax OP wished for.
#include <iostream>
#include <algorithm>
struct with_separator {
with_separator(std::string sep)
: sep(std::move(sep)) {}
std::string sep;
};
struct separated_stream {
separated_stream(std::ostream &stream, std::string sep)
: _stream(stream), _sep(std::move(sep)), _first(true) {}
template <class Rhs>
separated_stream &operator << (Rhs &&rhs) {
if(_first)
_first = false;
else
_stream << _sep;
_stream << std::forward<Rhs>(rhs);
return *this;
}
separated_stream &operator << (std::ostream &(*manip)(std::ostream&)) {
manip(_stream);
return *this;
}
private:
std::ostream &_stream;
std::string _sep;
bool _first;
};
separated_stream operator << (std::ostream &stream, with_separator wsep) {
return separated_stream(stream, std::move(wsep.sep));
}
int main()
{
std::cout << with_separator(", ") << 1 << 2 << 3 << std::endl;
}
Output :
1, 2, 3
Simple answer is No, however, you can roll your own...
#include <iostream>
#include <sstream>
using namespace std;
struct set_some_separator{
set_some_separator(const char* sep) : _sep(sep)
{ };
template <typename T>
set_some_separator& operator<<(const T& v)
{
_str << v << _sep;
return *this;
}
friend
ostream& operator<<(ostream& os, const set_some_separator& s)
{ return os << s._str.str(); }
const char* _sep;
ostringstream _str;
};
int main()
{
cout << (set_some_separator(" ") << 2 << 3 << 33 << 45) << endl;
}
Okay the format of the cout is slightly different, hey-ho...
Not quite the same thing, but:
#include <array>
#include <iostream>
#include <iterator>
int main() {
std::array<int, 3> data = { 1, 2, 3 };
std::ostream_iterator<int> out(std::cout, " ");
std::copy(data.begin(), data.end(), out);
std::cout << '\n';
return 0;
}
How about using the ostream_iterator
int main()
{
std::vector<int> data {2,3,33,45};
std::copy(std::begin(data), std::end(data),
std::ostream_iterator(std::cout, " "));
std::cout << "\n";
}
A C++17 fold expression with the comma operator can create a nice one-liner:
[](auto &&...xs){ ((std::cout << xs << ',') , ...); }(2,3,33,45);
Simple solution, maybe you can tweak it to use <<
template<typename T>
void myout(T value)
{
std::cout << value << std::endl;
}
template<typename First, typename ... Rest>
void myout(First first, Rest ... rest)
{
std::cout << first << " ";
myout(rest...);
}
myout('a',"Hello",1,2,3,22/7.0);
If you're just looking for a way to print a vector with its elements properly delimited (and without an extra delimiter at the end), try this:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3};
auto it = v.begin();
if (it != v.end())
{
std::cout << *it;
++it;
}
for (; it != v.end(); ++it)
{
std::cout << ", " << *it;
}
}
MyClass below represents a data structure that I need to be able to search very fast in two ways. So say I store the MyClass in and std::vector so that similar names in it can be quickly deleted and inserted continuously. But, I also need to be able to sort the contents of MyClass based on anInt. That is where an intrusive container (or Multimap) would sort the contents of a [very likely] unsorted std::vector. Two containers performing two very different duties on the same underlying items. Also, if I deleted the items from the std::vector they would also automatically disappear from the intrusive container.
Here is sort of the idea
#include <vector>
#include <iostream>
#include <vector>
#include <functional>
#include <boost/intrusive/unordered_set.hpp>
namespace bic = boost::intrusive;
std::hash<std::string> hash_fn;
struct MyClass : bic::unordered_set_base_hook<bic::link_mode<bic::auto_unlink>>
{
std::string name;
int anInt1;
mutable bool bIsMarkedToDelete;
MyClass(std::string name, int i) : name(name), anInt1(i), bIsMarkedToDelete(false) {}
bool operator==(MyClass const& o) const
{
return anInt1 == o.anInt1; // need the items in the intrusive container to sort on number
}
struct hasher
{
size_t operator()(MyClass const& o) const
{
//return hash_fn(o.name);
return o.anInt1; // need the items in the intrusive container to sort on number
}
};
};
std::ostream& operator << (std::ostream& out, const MyClass& ac)
{
out << ac.name << " " << ac.anInt1;
return out;
}
typedef bic::unordered_set<MyClass, bic::hash<MyClass::hasher>, bic::constant_time_size<false> > HashTable;
int main()
{
std::vector<MyClass> values
{
MyClass { "John", 0 },
MyClass { "Mike", 0 },
MyClass { "Dagobart", 25 },
MyClass { "John", 5 },
MyClass { "Mike", 25 },
MyClass { "Dagobart", 26 },
MyClass { "John", 10 },
MyClass { "Mike", 25 },
MyClass { "Dagobart", 27 },
MyClass { "John", 15 },
MyClass { "Mike", 27 }
};
HashTable::bucket_type buckets[100];
HashTable hashtable(values.begin(), values.end(), HashTable::bucket_traits(buckets, 100));
std::cout << "\nContents of std::vector<MyClass> values\n";
for(auto& e: values)
std::cout << e << " ";
std::cout << "\nContents of HashTable hashtable\n";
for(auto& b : hashtable)
std::cout << b << '\n';
std::cout << "\nContents of HashTable hashtable\n";
for(auto& b : hashtable)
std::cout << b << '\n';
#if 0 // This code won't compile since there is no operator [] for hashtable
for(int bucket = 0; bucket < 27; bucket++)
{
auto hit(hashtable[bucket].rbegin());
auto hite(hashtable[bucket].rend());
while (hit != hite)
{
MyClass mc = *hit;
std::cout << mc << " ";
hit++;
}
std::cout << '\n';
}
#endif // 0
std::cout << '\n';
std::cout << "values size first " << values.size() << '\n';
std::cout << "hash size fist " << hashtable.size() << '\n';
for(auto& e: values)
e.bIsMarkedToDelete |= ("Mike" == e.name);
std::cout << "removing all bIsMarkedToDelete";
for(auto& e: values)
if(e.bIsMarkedToDelete)
std::cout << e << " ";
std::cout << '\n';
// Note how easy and performance fast it is to delete items from the std::vector view
// I need the intrsive view to automatically update as well
values.erase(
std::remove_if(std::begin(values), std::end(values), std::mem_fn(&MyClass::bIsMarkedToDelete)),
std::end(values));
#if 0 // This code won't compile since there is no operator [] for hashtable
// If I did this now, it should show the "Mike" itens gone and the
/// rest of the items hanging off the same bucket still there.
for(int bucket = 0; bucket < 27; bucket++)
{
auto hit(hashtable[bucket].rbegin());
auto hite(hashtable[bucket].rend());
while (hit != hite)
{
MyClass mc = *hit;
std::cout << mc << " ";
hit++;
}
std::cout << '\n';
}
#endif // 0
std::cout << "values size now " << values.size() << '\n';
std::cout << "hash size now " << hashtable.size() << '\n';
std::cout << "Contents of value after removing elements " << '\n';
for(auto& e: values)
std::cout << e << " ";
std::cout << '\n';
values.clear();
std::cout << values.size() << '\n';
std::cout << hashtable.size() << '\n';
std::cout << "Done\n";
int j;
std::cin >> j;
}
You need fast lookups using different indices. This makes me think of Boost MultiIndex.
Next:
So say I store the MyClass in and std::vector so that similar names in it can be quickly deleted and inserted continuously
combined with
Also, if I deleted the items from the std::vector they would also automatically disappear
makes it clear you cannot escape the cost of keeping all indices up to date anyways. In which case, Boost Multi Index is as good as it gets.
Here's a sample:
Live On Coliru
#include <iostream>
#include <vector>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace bmi = boost::multi_index;
struct MyClass
{
std::string name;
int anInt1;
MyClass(std::string name, int i) : name(name), anInt1(i) {}
//bool operator==(MyClass const& o) const { return boost::tie(name, anInt1) == boost::tie(o.name, o.anInt1); }
//bool operator< (MyClass const& o) const { return boost::tie(name, anInt1) < boost::tie(o.name, o.anInt1); }
friend std::ostream& operator << (std::ostream& out, const MyClass& ac) {
return out << ac.name << " " << ac.anInt1;
}
};
using Table = bmi::multi_index_container<MyClass,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct as_vector> >,
bmi::ordered_non_unique<bmi::tag<struct by_number>,
bmi::member<MyClass, int, &MyClass::anInt1>
>,
bmi::hashed_non_unique<bmi::tag<struct by_name>,
bmi::member<MyClass, std::string, &MyClass::name>
>
>
>;
void alternative_remove_mikes(Table& values);
int main()
{
Table values {
{ "John", 0 },
{ "Mike", 0 },
{ "Dagobart", 25 },
{ "John", 5 },
{ "Mike", 25 },
{ "Dagobart", 26 },
{ "John", 10 },
{ "Mike", 25 },
{ "Dagobart", 27 },
{ "John", 15 },
{ "Mike", 27 },
};
auto& name_idx = values.get<by_name>();
std::cout << "\nBEFORE: Ordered by number:\n";
for(auto& e: values.get<by_number>())
std::cout << e << "\n";
std::cout << "\nBEFORE: O(1) lookup by name:\n";
for(auto& e : boost::make_iterator_range(name_idx.equal_range("Mike")))
std::cout << e << '\n';
std::cout << "removing all Mikes\n";
name_idx.erase("Mike");
// alternative_remove_mikes(values);
std::cout << "\nAFTER: Ordered by number:\n";
for(auto& e: values.get<by_number>())
std::cout << e << "\n";
std::cout << "\nAFTER: O(1) lookup by name:\n";
for(auto& e : boost::make_iterator_range(name_idx.equal_range("Mike")))
std::cout << e << '\n';
values.clear();
std::cout << "Done\n----------------------------\n";
}
If you want to keep the code to remove similar to the code you had (which is not optimal, but hey, just in case):
void alternative_remove_mikes(Table& values) {
// this uses the same `remove_if` approach together with the `rearrange()` feature of `random_access` index
std::vector<boost::reference_wrapper<MyClass const> > refs(values.begin(), values.end());
// remove_if is not good enough since it will leave the removed end unspecified
auto it = std::partition(refs.begin(), refs.end(), [](MyClass const& mc) { return "Mike" != mc.name; });
std::cout << "Removing " << std::distance(it, refs.end()) << " items:\n";
values.rearrange(refs.begin());
auto newend = values.begin() + std::distance(refs.begin(), it);
for (auto& e : boost::make_iterator_range(newend, values.end()))
std::cout << " -- removing " << e << "\n";
values.erase(newend, values.end());
}
Output:
BEFORE: Ordered by number:
John 0
Mike 0
John 5
John 10
John 15
Dagobart 25
Mike 25
Mike 25
Dagobart 26
Dagobart 27
Mike 27
BEFORE: O(1) lookup by name:
Mike 27
Mike 25
Mike 25
Mike 0
removing all Mikes
AFTER: Ordered by number:
John 0
John 5
John 10
John 15
Dagobart 25
Dagobart 26
Dagobart 27
AFTER: O(1) lookup by name:
Done
----------------------------