use operator << to push std::strings in a vector - c++

Is it possible to use operator<< to push strings into a vector. I searched a lot but only find stream examples.
class CStringData
{
vector< string > myData;
// ...
// inline operator << ... ???
};
I want this to use as a simple elipsis (like void AddData(...) ) exchange for
robust parameters.
CStringData abc;
abc << "Hello" << "World";
Is this possible at all ?

You can define operator<< as:
class CStringData
{
vector< string > myData;
public:
CStringData & operator<<(std::string const &s)
{
myData.push_back(s);
return *this;
}
};
Now you can write this:
CStringData abc;
abc << "Hello" << "World"; //both string went to myData!
But instead of making it member function, I would suggest you to make it friend of CStringData:
class CStringData
{
vector< string > myData;
public:
friend CStringData & operator<<(CStringData &wrapper, std::string const &s);
};
//definition!
CStringData & operator<<(CStringData &wrapper, std::string const &s)
{
wrapper.myData.push_back(s);
return wrapper;
}
The usage will be same as before!
To explore why should you prefer making it friend and what are the rules, read this:
When should I prefer non-member non-friend functions to member functions?

You need to use std::vector.push_back() or std::vector.insert() to insert elements inside a vector.

Following piece of code appends to stream. similary you can add it to vector also.
class CustomAddFeature
{
std::ostringstream m_strm;
public:
template <class T>
CustomAddFeature &operator<<(const T &v)
{
m_strm << v;
return *this;
}
};
as it is template so you can use it for other types also.

// C++11
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string>& operator << (vector<string>& op, string s) {
op.push_back(move(s));
return op;
}
int main(int argc, char** argv) {
vector<string> v;
v << "one";
v << "two";
v << "three" << "four";
for (string& s : v) {
cout << s << "\n";
}
}

Related

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

Overloading the ostream operator for a class wrapping stringstream

I'm currently writing a class to wrap stringstream. My overall goal is to provide a threadsafe << (ostream) for my stringstream. I'm having trouble figuring out the correct syntax of what I'm trying to do. Any help would be most appreciative!
Below you'll find what I've tried. I know this is not the correct syntax, but it is kind of what I'm shooting for. I could of course not overload the << operator and force users to use the AddValue, but that wouldn't be ideal for quick and easy string manipulation while writing the code.
class WrappedStringStream
{
public :
WrappedStringStream() ;
template<typename T>
void AddValue( const T & value )
{
m_mutex.Lock() ;
//here I'd like to do something like m_stringstream << value, but of course since
//I'm overloading operator<< that won't work
m_mutex.Unlock() ;
}
friend std::ostream & operator<<( std::ostream & out, const WrappedStringStream & string )
{
string.AddValue( out ) ;
return out ;
}
protected :
std::stringstream m_stringstream ;
mutable Mutex m_mutex ;
}
As mentioned above it doesn't compile, which I understand since I'm passing WrappedStringStream as a const parameter and calling AddValue which isn't const - resulting in the discards qualifier error.
Here is the solution
#include <iostream>
#include <sstream>
#include <mutex>
using namespace std;
class MutexWrapper
{
private:
mutex& m_mutex;
public:
MutexWrapper(mutex& mtx) : m_mutex(mtx) { mtx.lock () ; };
~MutexWrapper() { m_mutex.unlock () ; };
};
class WrappedStringStream
{
public :
WrappedStringStream() { };
template<typename T>
std::ostream & operator<<(const T& value)
{
MutexWrapper wrapper(m_mutex);
return m_stringstream << value;
}
void showStream()
{
cout << m_stringstream.str();
}
protected :
stringstream m_stringstream;
mutable mutex m_mutex ;
};
int main()
{
WrappedStringStream ws;
ws << "This is a string, " << 5 << 6.78;
ws.showStream();
return 0;
}
Output
This is a string, 56.78
======== edit ==========
Originally I was not quiet understand what the questioner's final goal, but just focus on how to fix his syntax issue.It is not a good idea to use << in a multithreading environment. We have a Log class, and in our log class we only have a Log method which takes variable amount of parameters. That will solve the problem.
Still, there is a solution for using << to lock the thread, but really urgly and NOT recommend. Downside is obvious - if you forgot to add the 'LoggingStart' and 'LoggingEnd', you might caught deadlock.
Also thanks #RemyLebeau, It should return *this instead of m_stringstream.
Please see code below.
#include <iostream>
#include <sstream>
#include <mutex>
using namespace std;
class WrappedStringStream
{
public:
enum StreamSignals
{
LoggingStart,
LoggingEnd
};
WrappedStringStream() { };
std::ostream & operator<<(const StreamSignals& signal)
{
if (signal == LoggingStart)
m_mutex.lock();
else if (signal == LoggingEnd)
m_mutex.unlock();
return *this;
}
template<typename T>
std::ostream & operator<<(const T& value)
{
m_stringstream << value;
return *this;
}
void showStream()
{
cout << m_stringstream.str();
}
protected :
stringstream m_stringstream;
mutable mutex m_mutex ;
};
int main()
{
WrappedStringStream ws;
ws << WrappedStringStream::StreamSignals::LoggingStart;
ws << "This is a string, " << 5 << 6.78;
ws << WrappedStringStream::StreamSignals::LoggingEnd;
ws.showStream();
return 0;
}

How to pass a parameter in C++ with the help of "=" operator

I have a class named Demo and in that class I have overloaded the Text() method for setting and getting it's private variable called text.
#ifndef DEMO_H
#define DEMO_H
#include <string>
#include <iostream>
using namespace std;
class Demo {
string text;
public:
Demo() {};
Demo(string newText) : text(newText) {};
void Text(string updatedText);
string Text();
};
#endif // !DEMO_H
void Demo::Text(string updatedText) {
text = updatedText;
}
string Demo::Text() {
return text;
}
Then in another class, I have used the method in following way-
#include "Demo.h"
int main()
{
Demo d;
d.Text("test");
cout << d.Text() << endl;
return 0;
}
This works fine. However, I want to set the parameter of the method with "=" operator. So rather than
d.Text("test");
I want to do
d.Text = "test";
Is it possible to achieve in C++ and if so then how. I was thinking of operator overloading but I couldn't achieve the goal. Can anyone please suggest.
The closest you can get in c++ to express property like getter / setter functions similar as in c# is to provide class member functions like these:
class Demo {
string text;
public:
void Text(const string& updatedText) { text = updatedText; }
const string& Text() const { return text; }
};
That idiom is used a lot in the c++ standard library like here.
I want to do
d.Text = "test";
What you can do is
class Demo {
public:
string& Text() { return text; }
};
and
d.Text() = "test";
but that totally defeats the concept of encapsulation of data.
The right way to proceed is overloading the assignment '=' operator and use as below.
class Demo {
string text;
public:
Demo() {};
Demo(string newText) : text(newText) {};
**void operator =(const string& val) { text = val; }**
void Text(string updatedText);
string Text();
};
int main()
{
Demo d;
//d.Text("test");
d = "hello world";
cout << d.Text() << endl;
return 0;
}
You could define your Text property as an object T. T could then overload some common property operations ( haven't figured out how a common getter call like Object o; o.set(d.Text); would be implemented yet ) :
#include <iostream>
using namespace std;
class T {
string _text;
public:
void operator =(const string& t) { _text = t; }
friend ostream& operator<<(ostream& os, const T& obj)
{
cout << obj._text;
return os;
}
};
class Demo {
public:
T Text;
};
int main()
{
Demo d;
d.Text = "test";
cout << d.Text << endl;
}

Stream object directly into a std::string

Given some type that is streamable:
struct X {
int i;
friend std::ostream& operator<<(std::ostream& os, X const& x) {
return os << "X(" << x.i << ')';
}
};
I want to append this onto a std::string. I can implement this as:
void append(std::string& s, X const& x) {
std::ostringstream os;
os << x;
s.append(os.str());
}
But this seems lame since I'm writing data into one stream just to then allocate a new string just for the purposes of appending it onto a different one. Is there a more direct route?
This can be solved by a new type of streambuf (see Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference).
Here is a sketch of how it can look:
#include <streambuf>
class existing_string_buf : public std::streambuf
{
public:
// Store a pointer to to_append.
explicit existing_string_buf(std::string &to_append);
virtual int_type overflow (int_type c) {
// Push here to the string to_append.
}
};
Once you flesh out the details here, you could use it as follows:
#include <iostream>
std::string s;
// Create a streambuf of the string s
existing_string_buf b(s);
// Create an ostream with the streambuf
std::ostream o(&b);
Now you just write to o, and the result should appear as appended to s.
// This will append to s
o << 22;
Edit
As #rustyx correctly notes, overriding xsputn is required for improving performance.
Full Example
The following prints 22:
#include <streambuf>
#include <string>
#include <ostream>
#include <iostream>
class existing_string_buf : public std::streambuf
{
public:
// Somehow store a pointer to to_append.
explicit existing_string_buf(std::string &to_append) :
m_to_append(&to_append){}
virtual int_type overflow (int_type c) {
if (c != EOF) {
m_to_append->push_back(c);
}
return c;
}
virtual std::streamsize xsputn (const char* s, std::streamsize n) {
m_to_append->insert(m_to_append->end(), s, s + n);
return n;
}
private:
std::string *m_to_append;
};
int main()
{
std::string s;
existing_string_buf b(s);
std::ostream o(&b);
o << 22;
std::cout << s << std::endl;
}
You could write a std::string casting operator:
struct X {
int i;
friend std::ostream& operator<<(std::ostream& os, X const& x) {
os << "X(" << x.i << ')';
return os;
}
operator std::string() {
return std::string("X(") + std::to_string(x.i) + ")";
}
};
Then, you could simply append it to a std::string:
X myX;
myX.i = 2;
std::string s("The value is ");
s.append(myX); //myX is cast into the string "X(2)"
In this specific case I'd just follow the KISS principle:
struct X {
int i;
std::string toString() const {
return "X(" + std::to_string(i) + ")";
}
};
Usage:
string += x.toString();
std::cout << x.toString();
An operator<<(std::ostream&, …) isn't really suitable for generic string conversion, so if that's what you're after then a toString type of method / free function is much better. And if you want std::cout << x you can trivially implement operator<< to just call toString.
Since the original string is likely only large enough for the existing allocation, the best you can hope for is to format everything you want to append once in the stream, then append the result as you have in your example.
If you plan on performing these appends often, I would argue std::string is the wrong type for the problem at hand. I would recommend using an std::ostringtream directly instead of a std::string, and only convert to a string when you need the final result.

Have a C++ Class act like a custom ostream, sstream

I have a C++ class MyObject and I want to be able to feed this data like I would to a osstream (but unlike a direct sstream, have the incoming data be formatted a special way). I can't seem to figure out how to overload a operator for MyObject to eat input given to it.
class MyObject {
public:
ostringstream s;
FEEDME
};
int main() {
MyObject obj;
obj.FEEDME << "Hello" << 12345;
// I want obj.s == ":Hello::12345:"
}
I want it so every item fed in be surrounded by : :
So in the given example, s = ":Hello::12345" should be the final outcome. What my question is, how can I tell the object that when ever a <<something, put : : around the something.
Is this possible?
try this:
class MyObject {
public:
template <class T>
MyObject &operator<<(const T &x) {
s << ':' << x << ':';
return *this;
}
std::string to_string() const { return s.str(); }
private:
std::ostringstream s;
};
MyObject obj;
obj << "Hello" << 12345;
std::cout << obj.to_string() << std::endl;
There are certain things you won't be able to shove into the stream, but it should work for all the basics.
You may find the answers for How do I create my own ostream/streambuf? helpful.
I would take a slightly different approach and create a formater object.
The formater object would then handle the inserting of format character when it is applied to a stream.
#include <iostream>
template<typename T>
class Format
{
public:
Format(T const& d):m_data(d) {}
private:
template<typename Y>
friend std::ostream& operator<<(std::ostream& str,Format<Y> const& data);
T const& m_data;
};
template<typename T>
Format<T> make_Format(T const& data) {return Format<T>(data);}
template<typename T>
std::ostream& operator<<(std::ostream& str,Format<T> const& data)
{
str << ":" << data.m_data << ":";
}
int main()
{
std::cout << make_Format("Hello") << make_Format(123);
}