std::map<std::string, std::vector<string>> data;
In order to print out this by using copy, how should my std::ostream_iterator be?
Apparently std::ostream_iterator<std::pair<std::string, std::vector<std::string>>> out_it(std::cout, "\n"); did not make it.
My operator<< overload is the following std::ostream& operator<<(std::ostream& out, const std::pair<std::string, std::vector<std::string>>& p) and it writes out the p.first and p.second and returns it.
If you do any serious programming in C++, you will eventually need a generic way to print out collections.
Here is the basis of one:
#include <iostream>
#include <map>
#include <vector>
#include <string>
// introduce the concept of an object that emits values to an ostream
// by default it simply calls operator <<
template<class T> struct emitter
{
using arg_type = T;
emitter(const T& v) : v_(v) {}
friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
return os << e.v_;
}
const T& v_;
};
// introduce the concept of an io manipulator called emit
template<class T> auto emit(const T& v) -> emitter<T>
{
return emitter<std::decay_t<T>>(v);
}
// specialise the emitter for maps
template<class K, class V, class C, class A>
struct emitter<std::map<K, V, C, A>>
{
using arg_type = std::map<K, V, C, A>;
emitter(const arg_type& v) : v_(v) {}
friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
const char* elem_sep = "\n\t";
const char* end_sep = " ";
os << "{";
for (const auto& elem : e.v_)
{
os << elem_sep << emit(elem.first) << ": " << emit(elem.second);
end_sep = "\n";
}
return os << end_sep << "}";
}
const arg_type& v_;
};
// specialise the emitter for vectors
template<class V, class A>
struct emitter<std::vector<V, A>>
{
using arg_type = std::vector<V, A>;
emitter(const arg_type& v) : v_(v) {}
friend std::ostream& operator<<(std::ostream& os, const emitter& e) {
const char* elem_sep = " ";
const char* end_sep = " ";
os << "[";
for (const auto& elem : e.v_)
{
os << elem_sep << emit(elem);
elem_sep = ", ";
}
return os << end_sep << "]";
}
const arg_type& v_;
};
int main() {
// build test data
std::map<std::string, std::vector<std::string>> data;
data.emplace("a", std::vector<std::string>{ "now", "is", "the", "time" });
data.emplace("b", std::vector<std::string>{ "for", "all", "good", "men" });
data.emplace("c", std::vector<std::string>{ "to", "come", "to", "the" });
data.emplace("d", std::vector<std::string>{ "aid", "of", "their", "party" });
// request an emitter manipulator
std::cout << emit(data) << std::endl;
}
Expected output:
{
a: [ now, is, the, time ]
b: [ for, all, good, men ]
c: [ to, come, to, the ]
d: [ aid, of, their, party ]
}
So here is a operator<< that will print out the contents of one pair from your map:
std::ostream& operator<<(std::ostream& out, const std::pair<std::string, std::vector<std::string>>& p) {
out << p.first << ": "; // prints the string from key
for (const auto& i : p.second) // loops throught the whole vector that is asociated with that key
out << i << ", ";
return out;
}
So to use it in this example. If you ennter this into your map:
std::map<std::string, std::vector<string>> data;
std::vector<std::string> vec = {"VAL1", "VAL2", "VAL3"};
data.insert(std::make_pair("KEY", vec));
auto it = data.find("KEY");
std::cout << *it;
This would be what wil get printed out using the operator<< above:
KEY: VAL1, VAL2, VAL3,
You can also change the formatting a bit so the comma isn't after the last value as well but that's only a cosmetic problem. Your problem was in that you wanted to print vector while it doesn't have std operator<<. So in order to print vector you must manually loop through it's content like in my example with the ranged for.
To custom print your vector, you'd have to write some code yourself. To make sure your custom operator is used, I suggest you use std::stringstream to turn your key-value pair into a string, which you'd then feed into an std::ostream_iterator<std::string>.
Something, like this (pardon the using namespace std;):
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <sstream>
#include <map>
using namespace std;
int main() {
map<string, vector<string>> m {
{"a", {"1", "2"}},
{"b", {"1", "2"}},
{"b", {"1", "2"}},
};
transform(begin(m), end(m), ostream_iterator<string>(cout), [](auto& p){
stringstream ss;
ss << p.first << ", {";
bool first = true;
for (auto& s : p.second)
{
ss << (first ? "" : ", ") << s;
first = false;
}
ss << "}\n";
return ss.str();
});
return 0;
}
I didn't actually write the operator<<, but you can substitue yours to make the lambda body short);
Related
I have a class Twhich has a map of string class T
For convinience, I would like to print the content in the class in an organized manner with tabulations.
As an example, I have:
#include <iostream>
#include <map>
#include <string>
class test;
typedef std::map<std::string, std::string> sMap;
typedef std::map<std::string, test> testMap;
class test {
public:
sMap map1;
testMap map2;
};
std::ostream& operator<<(std::ostream& os, const sMap& smap) {
for(const auto& s_smap : smap) {
os << s_smap.first
<< "\t"
<< s_smap.second
<< "\n";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const test& t) {
os << t.map1
<< "\n";
for (const auto& s_map : t.map2) {
os << s_map.first
<< "\t"
<< s_map.second
<< std::endl;
}
return os;
}
int main() {
sMap myMap;
myMap["a"] = "b";
test obj;
obj.map1 = myMap;
test obj2;
obj2.map2.insert({"one", obj});
obj2.map2["one"].map2.insert({"two", obj});
obj2.map2["one"].map2["two"].map2.insert({"three", obj});
obj2.map2["one"].map2["two"].map2["three"].map2.insert({"four", obj});
std::cout << obj2 << std::endl;
return 0;
}
I would like the output to be:
one a b
two a b
three a b
four a b
How can the operator<< be overloaded to achieve this?
Doing this means you need to pass along extra information. You could create a printMap kind of fucntion that takes an indentation level as an argument, but you've said you want to achieve this by overloading operator<< so you can't pass that along unless you wrap your test objects in another class/struct that does carry that info.
That might look something like the below, which outputs:
% ./a.out
a b
a b
a b
a b
Tweaking this is left as an exercise for the OP.
#include <iostream>
#include <map>
#include <string>
struct test;
using sMap = std::map<std::string, std::string>;
using testMap = std::map<std::string, test>;
struct test {
sMap map1;
testMap map2;
};
struct indent {
const test &ref;
int indentLevel;
indent(const test &ref, int indentLevel=0)
: ref(ref), indentLevel(indentLevel)
{ }
};
std::ostream& operator<<(std::ostream& os, const indent &i) {
int j = i.indentLevel;
for (const auto &[f, s] : i.ref.map1) {
for (int k = 0; k < j; k++) os << "\t";
os << f << "\t" << s << "\n";
}
for (const auto &[f, s] : i.ref.map2) {
os << indent(s, j + 1);
}
return os;
}
std::ostream& operator<<(std::ostream& os, const sMap& smap) {
for (const auto &[f, s] : smap) {
os << f << "\t" << s << "\n";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const test& t) {
os << t.map1
<< "\n";
for (const auto& s_map : t.map2) {
os << s_map.first
<< "\t"
<< s_map.second
<< std::endl;
}
return os;
}
int main() {
sMap myMap;
myMap["a"] = "b";
test obj;
obj.map1 = myMap;
test obj2;
obj2.map2.insert({"one", obj});
obj2.map2["one"].map2.insert({"two", obj});
obj2.map2["one"].map2["two"].map2.insert({"three", obj});
obj2.map2["one"].map2["two"].map2["three"].map2.insert({"four", obj});
std::cout << indent(obj2) << std::endl;
return 0;
}
Some aspects of this case incorporate post-C++11 features like structured bindings. If a newer standard cannot be used, these techniques can be converted to C++11 friendly constructs.
I have followed the solution given in the question of this topic, but I can't get it to work for my case.
I have the following
#include <iostream>
#include <utility>
#include <iomanip>
using namespace std;
template<class type>
class Array {
private:
int size;
pair<int,type>* base;
public:
Array() {}
Array(int min, int max, type v) {
size = max+min;
base = new pair<int,type>[size];
for(auto i = 0; i < size; i++)
base[i] = pair<int,type>(min+i,v);
}
~Array() { delete [] base; }
friend ostream& operator<<(ostream& os, Array& a) {
for(auto& b: a.base) {
os << "{key: " << setw(3) << b.first << "} {value: " << b.second << "}" << endl;
}
return os;
}
};
But the loop failed me when trying to iterate base,
I want to do it with the classic array, without using the vector of the stl
main.cpp:37:7: error: no matching function for call to ‘begin(std::pair*&)’
37 | for(auto& b: a.base) {
| ^~~
You can't use a range-for loop with a raw pointer, as there is no information available to the compiler about the size of the array the pointer is pointing at. Range-for loops only work with fixed arrays and containers which support begin/end iterators, like std::vector, which you should be using instead of new[], eg:
#include <iostream>
#include <utility>
#include <iomanip>
#include <vector>
using namespace std;
template<class type>
class Array {
private:
vector<pair<int,type>> base;
public:
Array() = default;
Array(int min, int max, type v) : base(max+min) {
for(auto& elem : base)
elem = make_pair(min++, v);
}
friend ostream& operator<<(ostream& os, const Array& a) {
for(auto& elem: a.base) {
os << "{key: " << setw(3) << elem.first << "} {value: " << elem.second << "}" << endl;
}
return os;
}
};
The system is able to figure out the type of each element using a.type().name() but seriously is not able to print them?
#include <iostream>
#include <vector>
#include <any>
#include <string>
#include <algorithm>
template<typename Last>
void addElement(std::vector<std::any>& container, Last last) {
std::cout << "Last = " << last << std::endl;
container.push_back(last);
}
template<typename First, typename... Rest>
void addElement(std::vector<std::any>& container, First first, Rest... rest) {
std::cout << "Elem = " << first << std::endl;
container.push_back(first);
addElement(container, rest...);
}
template<typename... Ts>
std::vector<std::any> createAnyVector(Ts... ts) {
std::vector<std::any> container;
addElement(container, ts...);
return container;
}
int main() {
std::cout << "ANYVECTOR" << std::endl;
std::vector<std::any> container = createAnyVector("Hello", 3.14, 'A', true, 42);
std::cout << "Number of elements in container = " << container.size() << std::endl; // 5 correct.
for (const auto& a : container) {
std::cout << a.type().name() << ", " << "HERE?" << std::endl;
}
}
If I just write a at the place where now HERE? stands, it returns the error:
No operator << matches these operands
operand types are: std::basic_ostream<char, std::char_traits<char>> << const << std::any
As the comments point out, you cannot do anything directly with std::any, you can just hold them.
If you control the API and have the option to create a wrapper around std::any, you can maintain a function pointer to print the current std::any's contents like so:
struct printable_any {
template <class T>
printable_any(T&& t) : m_val(std::forward<T>(t)) {
m_print_fn = [](std::ostream& os, const std::any& val) {
os << std::any_cast<std::decay_t<T>>(val);
};
}
private:
using print_fn_t = void(*)(std::ostream&, const std::any&);
std::any m_val;
print_fn_t m_print_fn;
friend std::ostream& operator<<(std::ostream& os, const printable_any& val) {
val.m_print_fn(os, val.m_val);
return os;
}
};
Note that even with this, you cannot take a random std::any and print it, you have to construct it yourself along with the function pointer.
Usage:
int main() {
std::vector<printable_any> vals {
"Hello", 3.14, 'A', true, 42
};
for (auto& v : vals) {
std::cout << v << '\n';
}
}
Prints
Hello
3.14
A
1
42
https://godbolt.org/z/o1sejrv1e
Well, what would this print:
struct Foo {
void *p;
};
any v = Foo{};
cout << v << '\n'; // what should this print?
There is no toString equivalent in C++. If you want that behavior, you may create your own hierarchy:
struct Printable {
virtual void print(ostream&) const = 0;
};
auto& operator<<(ostream& os, any const& obj) {
any_cast<Printable const&>(obj).print(os);
return os;
}
Or customize it as you wish and handle the error cases as you like, also add special cases for the integer types if you want, etc.
Does the vector have to be of type any or are you allowed to at least specify the kind of types that are stored in the vector? Because if you can at least specify which types are allowed, I recommend using std::variant.
example: std::vector<variant<int, string>> myVectorVariant;
After that, you can actually print to the console the items in your vector through the use of std::get_if from std::variant. copy-able function below to output your vector for the most of the main primitive types: int, float, char, string.
#include <variant>
#include <vector>
#include <iostream>
using namespace std;
void printVectorVariantValues(vector<variant<int, float, char, string>> arg) {
try {
for (auto val : arg) {
if (const auto intPtr (get_if<int>(&val)); intPtr)
cout << *intPtr << " ";
else if (const auto floatPtr (get_if<float>(&val)); floatPtr)
cout << *floatPtr << " ";
else if (const auto charPtr (get_if<char>(&val)); charPtr)
cout << *charPtr << " ";
else if (const auto stringPtr (get_if<string>(&val)); stringPtr)
cout << *stringPtr << " ";
}
} catch (bad_variant_access err) {
cout << "something" << " ";
}
cout << "DONE" << endl;
}
int main() {
vector<variant<int, float, char, string>> myVectorVariant = {1, 2, 'a', 'b', 3, 0.4f, 0.5f, "c", "DeF", 0.6f, "gHi", "JkL" };
printVectorVariantValues(myVectorVariant);
return 0;
}
/*
output below:
1 2 a b 3 0.4 0.5 c DeF 0.6 gHi JkL DONE
*/
I have something like this where Client and Order are classes :
std::vector<std::pair<Client,Order>> pair;
pair.push_back(std::make_pair(Client(2,"Anca"),Order(3,1)));
pair.push_back(std::make_pair(Client(16,"Maria"),Order(1,3)));
pair.push_back(std::make_pair(Client(29,"Alex"),Order(10,5)));
class Client{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date,std::string name){
dateWhenOrderWasPlaced=date;
clientName=name;
}
class Order{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza,int agePizza){
amountPizza=amPizza;
pizzaAge=agePizza;
}
And i can't figure out how to print this.I have tried in many ways :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<pair[it].first<< ", Second: " << pair[it].second <<std::endl;
}
}
And this :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<it.first<< ", Second: " << it.second <<std::endl;
}
}
And in the both ways i have error(first-no operator[] and second,no operator <<)
Your first attempt does not work because it is the actual pair but std::pair does not have an operator[]. Your second attempt is the correct way to go, but it does not work because you have not defined operator<< for your classes.
So, simply define operator<<, eg:
class Client
{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date, std::string name)
: dateWhenOrderWasPlaced(date), clientName(name)
{
}
friend std::ostream& operator<<(std::ostream &os, const Client &c)
{
// print c.dateWhenOrderWasPlaced and c.clientName to os as needed...
return os;
}
};
class Order
{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza, int agePizza)
: amountPizza(amPizza), pizzaAge(agePizza)
{
}
friend std::ostream& operator<<(std::ostream &os, const Order &o)
{
// print o.amountPizza and o.pizzaAge to os as needed...
return os;
}
};
void print(const std::vector<std::pair<Client,Order>> &pair)
{
for(const auto& it : pair)
{
std::cout << "First: " << it.first << ", Second: " << it.second << std::endl;
}
}
In my current project processes, distinguishable intervals, needs to be combined, if they are adjacent.
For this purpose I wanted to use the fantastic boost::icl library. Every process can be uniquely identified by its id.
First I'm adding some intervals to my interval_map. Now I wanted to accomplish two things:
Iterate over all occurring process-types (Here id=1,4,7)
Secondly, iterate over all processes being in a certain subset of kinds, in such a way that merging of overlapping intervals is automatically done.
This is what I got so far:
#include <iostream>
#include <set>
#include <boost/icl/interval_map.hpp>
#include "boost/icl/closed_interval.hpp"
struct Process {
int id;
};
bool operator==(const Process& p, const Process& q) {
return p.id == q.id;
}
bool operator<(const Process& p, const Process& q) {
return p.id < q.id;
}
std::ostream& operator<<(std::ostream& str, const Process& p) {
str << "Process{" << p.id << "}";
return str;
}
int main(int, char**) {
using namespace boost::icl;
interval_map<double, std::set<Process>> imap;
imap.add({ interval<double>::closed(0., 4.),{ Process{ 4 } } });
imap.add({ interval<double>::closed(2., 6.),{ Process{ 1 } } });
imap.add({ interval<double>::closed(4., 9.),{ Process{ 4 } } });
imap.add({ interval<double>::closed(8., 8.),{ Process{ 7 } } });
for (auto&& iter : imap) {
std::cout << iter.first << " - " << iter.second<< std::endl;
}
for (auto iter : find(imap, { Process{4} })) { // How to implement find on codomain
// Should print:
// [0.,4.] - { Process{4}}
// [4.,9.] - { Process{4}}
std::cout << iter.first << " - " << iter.second << std::endl;
}
}
First, an observation, since the intervals are closed, [0,4] and [4,6] aren't actually adjacent, but overlapping. Did you mean right_open?
Second, the interval map models a function, the mapping is not guaranteed to be injective.
In the limited scope of your example, it seems you'd rather invert the datastructure, to arrive at:
#include "boost/icl/closed_interval.hpp"
#include <boost/icl/interval_map.hpp>
#include <iostream>
#include <set>
#include <map>
struct Process {
int id;
friend bool operator==(const Process& p, const Process& q) { return p.id == q.id; }
friend bool operator<(const Process& p, const Process& q) { return p.id < q.id; }
friend std::ostream& operator<<(std::ostream& str, const Process& p) {
return str << "Process{" << p.id << "}";
}
};
int main(int, char**) {
using namespace boost::icl;
using Map = std::map<Process, boost::icl::interval_set<double> >; // instead of boost::icl::interval_map<double, std::set<Process> >;
using IVal = Map::mapped_type::interval_type;
Map imap;
imap[{4}] += IVal::right_open(0, 4);
imap[{1}] += IVal::right_open(2, 6);
imap[{4}] += IVal::right_open(4, 9);
imap[{7}] += IVal::closed(8, 8);
//for (auto&& el : imap) { std::cout << el.first << " - " << el.second << std::endl; }
Process key{4};
std::cout << key << " - " << imap[key];
}
This results in:
Process{4} - {[0,9)}
Which is what I think you meant with "in such a way that merging of overlapping intervals is automatically done".
Having Both
Of course you can derive the inverse mappings from the original data-structure:
template <typename IMap>
auto inverted(IMap const& imap) {
std::map<typename IMap::codomain_type::value_type, boost::icl::interval_set<typename IMap::domain_type> > output;
for (auto& el : imap)
for (auto& key: el.second)
output[key] += el.first;
return output;
}
See it Live On Coliru
#include "boost/icl/closed_interval.hpp"
#include <boost/icl/interval_map.hpp>
#include <iostream>
#include <set>
struct Process {
int id;
friend bool operator==(const Process& p, const Process& q) { return p.id == q.id; }
friend bool operator<(const Process& p, const Process& q) { return p.id < q.id; }
};
std::ostream& operator<<(std::ostream& str, const Process& p) {
str << "Process{" << p.id << "}";
return str;
}
template <typename IMap>
auto inverted(IMap const& imap) {
std::map<typename IMap::codomain_type::value_type, boost::icl::interval_set<typename IMap::domain_type> > output;
for (auto& el : imap)
for (auto& key: el.second)
output[key] += el.first;
return output;
}
int main(int, char**) {
using namespace boost::icl;
using IMap = boost::icl::interval_map<double, std::set<Process> >;
using IVal = IMap::interval_type;
IMap imap;
imap.add({ IVal::right_open(0, 4), {Process{ 4 }} });
imap.add({ IVal::right_open(2, 6), {Process{ 1 }} });
imap.add({ IVal::right_open(4, 9), {Process{ 4 }} });
imap.add({ IVal::closed(8, 8), {Process{ 7 }} });
std::cout << imap << "\n\n";
for (auto&& iter : imap) {
std::cout << iter.first << " - " << iter.second << std::endl;
}
Process key{4};
std::cout << key << " - " << inverted(imap)[key] << "\n";
}
More Notes
Querying multiple keys in the domain is directly supported, see a good assortion of pointers here:
split_interval_map usage, efficient find all interval intersecting a point
boost multi_index_container search for records that fall within intervals defined by two fields
You can always construct your own data-structure that affords bi-directional indexes, such as shown e.g.
here boost::multi_index_container, operations on std::set inside container