Overload operator<< for a vector struct of pointer? - c++

I am currently trying to make a overload operator<< to my vector of structs, such that I will print the content of the vector in a matrix format..
this is what I've tried so far
// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
struct element
{
std::vector<int> keys;
std::string item;
element(std::vector <int> key, std::string item)
{
keys = key;
this->item = item;
}
};
inline std::stream operator << (std::ostream &stream, const std::vector<element*> _element)
{
for (auto elements: _element)
{
for(auto item : elements)
{
std::stream << item.key << " "
}
}
}
int main()
{
std::cout << "Hello, Wandbox!" << std::endl;
std::vector<element> storage;
std::vector<int> test(10);
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
std::string name = "test";
storage.push_back(element(test,name));
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
storage.push_back(element(test,name));
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
storage.push_back(element(test,name));
std::vector<element*> copy_of_storage;
for(auto elements: storage)
{
copy_of_storage.push_back(&(elements));
}
std::cout << copy_of_storage << std::endl;
}
but for some reason it is not working, and can't seem to understand what is going wrong?
https://wandbox.org/permlink/BQpqmz0HwoXgyS7t

There are a lot of things that are wrong in your operator<<.
First, your return type should be std::ostream& thus you must return stream. In your second loop :
for(auto item : elements)
elements is a pointer of element (the value type of your vector) so you can't iterate other it, you might want to iterate other elements->keys
Here is your fixed function :
inline std::ostream& operator<< (std::ostream &stream, const std::vector<element*> _element)
{
for (auto elements: _element)
for(auto item : elements->keys)
stream << item << " ";
return stream;
}
https://wandbox.org/permlink/qNYVx2yMg7L76NWe

There are quite a few things you can do to fix your code example - better naming conventions would be an important start.
The reason your code doesn't work is because of your operator << function. The following will work:
std::ostream& operator << (std::ostream &stream, std::vector<element*> _elements)
{
for (auto element : _elements)
{
for(auto item : element->keys)
{
stream << item << " ";
}
}
return stream;
}
Your working example: https://wandbox.org/permlink/FVXbLlXEAJpVbfAx
Furthermore:
Refactor your code - better variable names.
Try to use the member initialisation list in the element constructor.
And might be worth changing the ctor params to const &.
operator << should return a std::ostream&.
remove the inline keyword
in the operators << param list, you can remove the const from the std::vector<element*> since it is a copy of a vector that contains non-const pointers.

Related

How can I print map key/value with std::variant?

I'm trying to print the key of a certain value in my dictionary. I defined my map like this:
std::map<std::string, std::variant<float,int,bool,std::string>> kwargs;
kwargs["interface"] = "probe";
kwargs["flag"] = true;
kwargs["Height"] = 5;
kwargs["length"] = 6;
I tried to print the value normally but a (no operator "<<" matches these operands) error occurs.
std::cout << kwargs["flag"] << std::endl;
Can someone help me with this error?
There's no operator<< for std::variant, which can't be printed out directly. You need to read the value from the variant (by index or type), e.g.
std::cout << std::get<bool>(kwargs["flag"]) << std::endl;
Or
std::cout << std::get<2>(kwargs["flag"]) << std::endl;
You can define operator<< for your type:
std::ostream& operator<<(std::ostream& os, std::variant<float,int,bool,std::string> const& v) {
std::visit([&os](auto const& x) { os << x; }, v);
return os;
}
You can generalize the solution to work with any variant specialization:
template <class Var, class = std::variant_alternative_t<0, Var>>
std::ostream& operator<<(std::ostream& os, Var const& v) {
std::visit([&os](auto const& x) { os << x; }, v);
return os;
}
Note, the second template parameter exists to disable the definition if the Var is not a std::variant specialization.
I would use std::visit with a generic lambda that prints any type to std::cout, as follows:
std::map<std::string, std::variant<float,int,bool,std::string>> kwargs;
kwargs["interface"] = "probe"s;
kwargs["flag"] = true;
kwargs["Height"] = 5;
kwargs["length"] = 6;
for (const auto& [k, v] : kwargs){
std::cout << k << " : ";
std::visit([](const auto& x){ std::cout << x; }, v);
std::cout << '\n';
}
This works because all of float, int, bool, and std::string have overloads for the output stream operator <<. For other types, or to override this behaviour, you could use a custom functor class instead of a lambda:
struct PrintVisitor {
template<typename T>
void operator()(const T& t) const {
std::cout << t;
}
// prints std::string in quotes
void operator(const std::string& s) const {
std::cout << '\"' << s << '\"';
}
};
[...]
std::visit(PrintVisitor{}, kwargs);
NOTE: unfortunately, the line kwargs["interface"] = "probe"; doesn't actually select the std::string constructor for the variant type, because the string literal preferentially converts to a bool rather than a std::string (further reading). You can avoid this by explicitly making a std::string using, for example, std::string{"probe"} or the standard std::string user-defined literal, as in "probe"s.
Live demo

C++ Sorting vector of structs with const variables alphabetically

Hello I wanted to know if it was possible to do a thing like this ? // THANKS ! :)
struct PET
{
const char* pet;
const int age;
};
bool Sort(const PET& first, const PET& second)
{
return first.pet < second.pet;
}
void Foo(const std::vector<PET> pets)
{
std::sort(pets.begin(), pets.end(), Sort); /* Does not work */
std::cout << pets[0].pet;
std::cout << pets[0].age;
}
I completely agree with # Ulrich Eckhardt.
You cannot sort the vector as because the elements of your vector are not assignable.
I think, you might have gone confused with usage of const.
There is no need to make the structure variables const. The parameter of the custom sort function are generally kept as const because they should not be modifiable. This is a pattern which ensures safe coding practice.
Also, if you are using C++, I would suggest to use std::string instead of char*, as std::string is a cleaner, safer way to go because it removes the burden of memory management from the programmer.
Have a look at the working implementation, without use of const:
#include <string.h>
#include<iostream>
#include<vector>
#include<algorithm>
struct PET
{
std::string name;
int age;
};
bool compare(const struct PET& a, const struct PET& b){
return (a.name.compare(b.name) <= 0) ? true : false;
}
int main(){
std::vector<struct PET> vec(3);
vec[0].name = "dog";
vec[0].age = 3;
vec[1].name = "cat";
vec[1].age = 1;
vec[2].name = "bird";
vec[2].age = 2;
sort(vec.begin(), vec.end(), compare);
for(int i=0;i<3;i++){
std::cout<<vec[i].name<<" "<<vec[i].age<<std::endl;
}
return 0;
}
As #Deepak Tatyaji Ahire and #Ulrich Eckhardt said, you can't do what you wrote in your code.
const int can't be a variable. It is a constant for definition :)
The vector you wrote in your code can't be built that way.
I did not understand what you wanted to do with the "sort" function, I wrote the following to code, maybe it could help:
#include<iostream>
#include<vector>
struct PET
{
const char* pet;
int age;
PET(const char* c, int a) : pet(c) , age(a) {}
};
void Foo(PET &p, std::vector<PET> &v)
{
v.push_back(p);
/*do something here if needed*/
}
int main()
{
std::vector<PET> vect;
PET cat("Cat", 5);
PET dog("Dog", 10);
PET bird("Bird", 2);
Foo(cat, vect);
Foo(dog, vect);
Foo(bird, vect);
/*this is not elegant, you could define a function that give a list of
({Animal, age},...) to vector and then pushes back all these elements to the vector*/
for(int i=0; i<3; i++) std::cout<< vect[i].pet << ' ' << vect[i].age << std::endl; //std::cout << vect; if you are using an operator << overload
/*to overload the << operator in order to able to print the vector of struct PET:
std::ostream & operator << (std::ostream &os, std::vector<PET> &p)
{
os << "<";
for (int i = 0; i < p.size(); i++) {
os << p[i].pet;
os << ", ";
os << p[i].age;
if (i != p.size() - 1)
os << " - ";
}
os << ">\n";
return os;
}
*/
return 1;
}
AFAIK, there's no way to directly compare structures without defining their comparator.
Though in C++20, it introduces three-way comparison and you might be allowed to declare the Default comparisons by a single line. Very convenient. Unfortunately, there haven been no compiler implementing this feature.
For now, you have to manually define the comparator
inline bool cmp(const PET &lhs, const PET &rhs)
{
return std::strcmp(lhs.pet, rhs.pet)<0;
}
and pass it to std::sort

Narrowing down a C++ concept to exclude certain types

Suppose I would want to overload the left shift operator for ostreams and all containers.
This is what I'm currently have (compile with -fconcepts):
#include <vector>
#include <iostream>
template<typename Container>
concept bool Iterable = requires(Container t) {
{ *t.begin()++, t.end() };
};
template<Iterable T>
std::ostream& operator<<(std::ostream& out, const T& t) {
for(const auto& it: t) {
out << it << " " ;
}
return out;
}
int main() {
std::vector<int> a = {1, 2, 3};
std::cout << a << std::endl;
std::string str = "something";
// std::cout << str << std::endl; // compile error if the template is defined
return 0;
}
The problem however, is that this there is already a version of the ostream&<< for std::string.
Is there a general (something like a requires not expression) or specific (maybe similar to partial specialization by which I can exclude concrete classes) way to exclude something in a concept?
If not, what is the correct way around this?
template<Iterable T>
requires !requires(std::ostream o, T a) { operator<<(o, a); }
std::ostream& operator<<(std::ostream& out, const T& t) {
for(const auto& it: t) {
out << it << " " ;
}
return out;
}
Add a requirement that the type does not already have an operator<< defined. I am not 100% sure this should work, but it does work on gcc.
(simply o << a crashes gcc)

How to use lower_bound to insert value into sorted vector

I have a vector of pointer to class A which I want to keep sorted by int key using STL. To do this I defined an operator < in class A
bool operator< (const A &lhs, const A &rhs){
return (lhs.key < rhs.key);
};
and in my insert function it looks like
vector<A*>::iterator it = lower_bound(vec.begin(), vec.end(), element);
vec.insert(it, element);
I expect lower_bound to return first place where the new element can be placed, but it does not work. Inserting A objects with keys 0,1,2,3 will result in vector in incorrect order (2,3,1,0). Why is that ?
Probably I could also use comparator for this object:
compare function for upper_bound / lower_bound
but what's wrong with my code?
From your example, you're using a vector of pointers: std::vector<A*>. Hence, you need to define a comparison for pointers which you pass in to std::lower_bound:
bool less_A_pointer (const A* lhs, const A* rhs)
{
return (lhs->key < rhs->key);
}
auto it = std::lower_bound(vec.begin(), vec.end(), element, less_A_pointer);
//...
Of course, the question is why are you using pointers in the first place - just store A objects unless you really need to. If you do need to store pointers, look into std::shared_ptr which will handle this for you:
std::vector<std::shared_ptr<A>> v;
std::shared_ptr<A> element(new A(...));
auto it = std::lower_bound(v.begin(), v.end(), element); //Will work properly
You can also use a lambda instead of having to write a free function:
auto it = std::lower_bound(v.begin(), v.end(),
[](const A* lhs, const A* rhs)
{ return lhs->key < rhs->key; });
If you really want a std::vector of pointers, you may want to consider using a smart pointer like std::shared_ptr.
Raw pointers are OK if they are observing pointers, but generally you should not using raw owning pointers (unless in some special conditions).
You can pass a lambda to std::lower_bound(), to specify the sorting criteria (in this case, compare the key data members).
Moreover, instead of explicitly writing std::vector<std::shared_ptr<A>>::iterator for the return value of std::lower_bound(), you could just use C++11's auto keyword, which makes the code more readable in this case.
A compilable code sample follows (compiled with g++ 4.8.0):
#include <algorithm> // for std::lower_bound
#include <iostream> // for console output
#include <memory> // for std::make_shared, std::shared_ptr
#include <string> // for std::string
#include <vector> // for std::vector
using namespace std;
// Test data structure
struct A
{
int Key;
string Data;
A()
: Key(0)
{}
A(int key, const string& data)
: Key(key), Data(data)
{}
};
ostream& operator<<(ostream& os, const A& a)
{
os << "(key=" << a.Key << ", data=\"" << a.Data << "\")";
return os;
}
void Print(const vector<shared_ptr<A>> & v)
{
cout << "[ ";
for (const auto & p : v)
{
cout << *p << " ";
}
cout << " ]\n";
}
int main()
{
// Test container
vector<shared_ptr<A>> v;
// Test data
const char* data[] = {
"hello",
"world",
"hi",
nullptr
};
// Index in data array
int i = 0;
// Insertion loop
while (data[i] != nullptr)
{
// Create new element on the heap
auto elem = make_shared<A>(i, data[i]);
// Find ordered insertion position
auto it = lower_bound(v.begin(), v.end(), elem,
[](const shared_ptr<A>& lhs, const shared_ptr<A>& rhs)
{
return lhs->Key < rhs->Key;
}
);
// Insert in vector
v.insert(it, elem);
// Move to next data
i++;
}
// Show the result
Print(v);
}
Here's the output:
[ (key=2, data="hi") (key=1, data="world") (key=0, data="hello") ]

how to print out all elements in a std::stack or std::queue conveniently

If I do not to want to create a new container in order to do so?
I've written a snippet to do that for debugging. For example:
std::stack<int> s; // works with std::queue also!
s.push(1);
s.push(2);
std::cout << s; // [ 1, 2 ]
Please forgive me for this hackish code! but this is what I've written months ago:
#include <stack>
#include <queue>
#include <ostream>
template <class Container, class Stream>
Stream& printOneValueContainer
(Stream& outputstream, const Container& container)
{
typename Container::const_iterator beg = container.begin();
outputstream << "[";
while(beg != container.end())
{
outputstream << " " << *beg++;
}
outputstream << " ]";
return outputstream;
}
template < class Type, class Container >
const Container& container
(const std::stack<Type, Container>& stack)
{
struct HackedStack : private std::stack<Type, Container>
{
static const Container& container
(const std::stack<Type, Container>& stack)
{
return stack.*&HackedStack::c;
}
};
return HackedStack::container(stack);
}
template < class Type, class Container >
const Container& container
(const std::queue<Type, Container>& queue)
{
struct HackedQueue : private std::queue<Type, Container>
{
static const Container& container
(const std::queue<Type, Container>& queue)
{
return queue.*&HackedQueue::c;
}
};
return HackedQueue::container(queue);
}
template
< class Type
, template <class Type, class Container = std::deque<Type> > class Adapter
, class Stream
>
Stream& operator<<
(Stream& outputstream, const Adapter<Type>& adapter)
{
return printOneValueContainer(outputstream, container(adapter));
}
You can stream std::stack and std::queue just like any other supported type!
You can't iterate through a stack or a queue. In fact, SGI's documentation says this (it's about stack, but it's the same reason for queue):
This restriction is the only reason for stack to exist at all. Note that any Front Insertion Sequence or Back Insertion Sequence can be used as a stack; in the case of vector, for example, the stack operations are the member functions back, push_back, and pop_back. The only reason to use the container adaptor stack instead is to make it clear that you are performing only stack operations, and no other operations.
So, if you really want to do this, you'll have to empty the stack (or queue):
std::stack<Whatever> s;
// ...
while(!s.empty())
{
Whatever w = s.top();
std::cout << w;
s.pop();
}
ostream & operator<<(ostream & os, stack<double> my_stack) //function header
{
while(!my_stack.empty()) //body
{
os << my_stack.top() << " ";
my_stack.pop();
}
return os; // end of function
}
/*
using this simple overloaded operator function, you're able to print out all the components of a stack by doing a simple cout << your_stack_name;*/
It can be easily done using recursion you just need to know when to re-add the next element
For Stack
void print(stack<char> &s)
{
if(s.empty())
{
cout << endl;
return;
}
char x= s.top();
s.pop();
print(s);
s.push(x);
cout << x << " ";
}
And this one is For Queue
void print(queue<char> &s,int num)
{
if(!num)
{
cout << endl;
return;
}
char x= s.front();
s.pop();
cout << x << " ";
s.push(x);
print(s,--num);
}
Good Luck
Posting b/c I found this useful for debugging. Pop from original into a temp and then pop from temp back into original:
template <typename T>
void dump_stack(std::stack<T>& stack) {
std::stack<T> temp;
while (!stack.empty()) {
T top = stack.top(); stack.pop();
std::cout << top << " ";
temp.push(top);
}
while (!temp.empty()) {
T top = temp.top(); temp.pop();
stack.push(top);
}
}
If you need to do this, then stack or queue is not the correct choice of container.
If you still insist on doing this, the best way is to make a copy and pop elements off of it and print them. I'm not going to suggest another way because there's no point.
I've found solution which should work with all implementations (IMO) of std::stack, but unfortunately the stack must use std::vector instead of queue.
template<typename T>
void printStack(const std::stack<T, std::vector<T>>& s)
{
typedef typename std::stack<T>::const_reference EntryTypeRef;
typedef std::remove_reference_t<EntryTypeRef> EntryType;
for(size_t i=0; i < s.size(); ++i)
{
EntryType* e = &s.top();
cout << *(e-i) << endl;
}
}
std::vector is dynamic array, so we can use pointer arytmetics.
The marked answer to the question assumes, that the stack has field named 'c', I have another solution which would work with std::stack implementation which has container as first field, but its name does not matter:
template<typename T>
void printStack(const std::stack<T>& s)
{
typedef typename std::stack<T>::container_type Container;
const auto containerPtr = reinterpret_cast<const Container*>(&s);
for(auto e : *containerPtr)
cout << e << endl;
}
Try this:
template<typename T, typename C>
struct myStack : std::stack<T, C> {
typedef std::stack<T, C> Stack;
using Stack::stack;
using Stack::c;
};
int main()
{
myStack<int, std::deque<int>> s;
s.push(1);
s.push(2);
std::deque<int>::iterator it = s.c.begin();
while (it != s.c.end())
std::cout << ' ' << *it++;
}
Here we expose underlying container of std::stack as member c.