C++ streams operator << and manipulators / formatters - c++

First, most of my recent work was Java. So even though I "know" C++, I do not want to write Java in C++.
And C++ templates are one thing I will really miss when going back to Java.
Now that this out of the way, if I want to do create a new stream formatter, say pic, that will have a single std::string parameter in it's constructor.
I would like the user to be able to write something like:
cout << pic("Date is 20../../..") << "100317" << endl;
The output should be
Date is 2010/03/17
How do I write the pic class? when the compiler sees the cout what are the underlying steps the compiler does?
Edit
Would it be more C++ to change that code into:
cout << pic("Date is 20../../..", "100317") << endl;
And possibly be easier to write the pic function as a standalone function (possibly template)?

It sounds like you are trying to write an alternate form of printf(). I'm not sure that this is a good idea, but if you decide to do it, you should definitely write it as a free function, because the manipulator issues (which have nothing to do with formatting using a format string) go away. I would also avoid templates to start with, and simply design and write the string version:
void pic( ostream & os, const string & fmt, const string & val );
Before writing such a function, you will have to be very clear in your mind what its semantics are, which I don't believe you are yet.

you might have a look at boost::format library.
somethings like this should work (if you can afford spliting your string first)
#include <iostream>
#include <string>
#include <boost/format.hpp>
int main()
{
const char* a = "102030";
std::string year(a, a + 2);
std::string month(a + 2, a +4);
std::string day(a + 4);
std::cout << boost::format("Date is 20%1%/%2%/%3%")% year % month % day << std::endl;
}

There are 2 questions here.
One deals with stream manipulators, follow the quote.
The other one deals with formatting issues.
Formatting is hard, especially the way you indicate it, because it involves being able to parse the format and generate an AST representation that will then be called to actually format the string. Parsing means that you need to define a small grammar etc...
There are libraries like Boost.Spirit who deals with parsing / generating, and they are much more complicated than the 'simple' Boost.Format (which itself is not that simple).
Now, could you forgo parsing ?
class Date
{
public:
Date(year_t year, month_t month, day_t day);
year_t getYear() const;
month_t getMonth() const;
day_t getDay() const;
private:
year_t mYear;
month_t mMonth;
day_t mDay;
};
The advantage of this class are multiple:
Structured information: parses one, reads as much as you wish
Validation: root out invalid date (29 Feb 2010 ?)
No ambiguity: is "100102" actually the "1st Feb 2010" or "2nd Jan 2010" ? (at least not once it's parsed)
Then, you can do the same for the format, by creating a little formatting engine.
template <class T>
class Formatter
{
public:
virtual ~Formatter() {}
virtual Formatter* clone() const = 0;
virtual std::string evaluate(const T& item) const = 0;
};
template <class T>
class FormatterConstant: public Formatter
{
public:
explicit FormatterConstant(const std::string& s): mValue(s) {}
virtual Formatter<T>* clone() const { return new FormatterConstant(*this); }
virtual std::string evaluate(const T&) const { return mValue; }
private:
std::string mValue;
};
template <class T>
class FormatterComposite: public Formatter<T>
{
typedef std::vector< const Formatter<T>* > formatters_type;
typedef typename formatters_type::const_iterator const_iterator;
public:
// Need suitable Copy and Assignment Constructors
~FormatterComposite()
{
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) delete *it;
}
virtual Formatter<T>* clone() const { return new FormatterComposite(*this); }
virtual std::string evaluate(const T& item) const
{
std::string result;
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) result += (*it)->evaluate();
return result;
}
void imbue(std::ostream& s) { mStream = &s; }
FormatterComposite& operator<<(const std::string& s)
{
mFormatters.push_back(new FormatterConstant<T>(s); }
return *this;
}
FormatterComposite& operator<<(const Formatter<T>& formatter)
{
mFormatters.push_back(formatter.clone());
return *this;
}
std::ostream& operator<<(const T& item) const
{
return (*mStream) << this->evaluate(item);
}
private:
std::ostream* mStream;
formatters_type mFormatters;
};
template <class T>
FormatterComposite& operator<<(std::ostream& s, FormatterComposite& c)
{
c.imbue(s);
return c;
}
// Usage
class DateOfYear: public Formatter<Date>
{
public:
Formatter<Date>* clone() const { return new DateOfYear(*this); }
std::string evaluate(const Date& d) const { return toString(d.getYear()); }
};
extern const DateOfYear year;
int main(int argc, char* argv[])
{
FormatterComposite<Date> formatter;
Date date;
std::cout << formatter << "Date is 20"
<< year << "/" << month << "/" << day << date;
return 0;
}
Here, you forgo parsing. Of course it means the format is hardcoded...

Here is the initial solution to what I did. Only issue is that I'm still not able to templatize it. If I do, then calling the pic formatter would look like pic<float>("$(...)", 2.56) and the code would be messy.
#include <iostream>
#include <string>
using namespace std;
class pic {
private:
const string& _v;
const string& _pic;
public:
pic(const string& p, const string& v) : _v(v), _pic(p) {
}
friend ostream & operator<<(ostream& os, const pic& p) {
bool done = false;
int pi = 0;
int vi = 0;
while (!done) {
os << (p._pic[pi] == '.' ? p._v[vi++] : p._pic[pi]);
done = ++pi > p._pic.length() || vi > p._v.length();
}
return os;
}
};
int main(int argc, char** argv) {
cout << "The formatted date is: " << pic("20../../..", "100317") << endl;
return 0;
}

Related

How can I static cast the output of the >> operator in c++?

Or perform any function really.
Currently I have some code that looks a bit like this:
int temp_int;
streamer >> temp_int;
finalObj = static_cast<CustomType>(temp_int);
ints can be cast into CustomTypes (obviously) and finalObj is of type CustomType
streamer's >> operator has not been set up to work with CustomType. Changing this is outside my area of control.
Im looking for a way to put the above code in a single line and avoid using a temporary variable.
When putting custom types back into the streamer, I use this:
streamer << static_cast<int>(someObj);
Thats a lot neater. And it would be great to have the instreaming and outstreaming look symmetrical for easier reading.
Thanks
Just implement an operator>> and make sure name lookup finds it.
struct CustomType
{
int m_value;
CustomType(int v = 0)
: m_value(v)
{}
operator int() const
{
return m_value;
}
};
namespace
{
std::istream& operator>>(std::istream& s, CustomType& out)
{
int temp;
s >> temp;
out = temp;
return s;
}
}
int main()
{
CustomType finalObj;
std::cin >> finalObj;
std::cout << finalObj << '\n';
}
Alternatively, if you aren't sure, if operator>> has already been implemented somewhere in an undesired manner, you could create a wrapper type and implement operator>> for it.
namespace
{
class CustomTypeParsingWrapper
{
public:
CustomTypeParsingWrapper(CustomType& target)
: m_target(target)
{
}
friend std::istream& operator>>(std::istream& s, CustomTypeParsingWrapper const& wrapper)
{
int temp;
s >> temp;
wrapper.m_target = temp;
return s;
}
private:
CustomType& m_target;
};
}
int main()
{
CustomType finalObj;
std::cin >> CustomTypeParsingWrapper(finalObj);
std::cout << finalObj << '\n';
}
Note: The use of the anonymous namespace here is only to avoid conflicts with implementations provided to other translation units. If you want to reuse operator>>, you should put it in the same namespace as CustomType to allow Argument Dependent Lookup to find it. A customTypeParsingWrapper intended to be reused could be put in a namespace of your choice...
One way to achieve what you want is to overload not only << and >> operators, but also the cast operator.
One way to do that is to overload the int() operator for CustomType. This way, you can use put your value back into the streamer easily:
class CustomType
{
private:
int _value;
public:
CustomType(const int &value) : _value(value) {}
// ...
operator int() const { return _value; }
};
This way, the compiler will find the appropriate cast from CustomType to int when using the << operator:
streamer << someObj;
will implicitly cast to int.
Similar overloads could be implemented to achieve the results.
Here is a full snipped to test this:
#include <iostream>
class CustomType
{
private:
int _value;
public:
CustomType(const int &value) : _value(value) {}
// ...
operator int() const { return _value; }
};
int main() {
auto someObj = CustomType(10);
std::cout << someObj;
}
This prints 10 to the standard output.

Forward declaration not working in c++. It says initialization of incomplete type

I am learning design patterns and I am trying to implement builder pattern. For this purpose I am compiling below code with "clang++ -std=c++17" but I am getting error "error: initialization of incomplete type 'HtmlBuilder'" where I am returning in static function HtmlElement::build. How to solve this issue?
class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
string name, text;
vector<HtmlElement> elements;
const size_t indent_size = 2;
HtmlElement() {}
HtmlElement(const string &name, const string &text): name(name), text(text) {}
public:
string str(int indent = 0) const
{
ostringstream oss;
string i(indent_size*indent, ' ');
oss << i << "<" << name << ">" << endl;
if (text.size() > 0)
{
oss << string(indent_size * (indent + 1), ' ') << text << endl;
}
for (const auto& e: elements)
{
oss << e.str(indent + 1);
}
oss << i << "</" << name << ">" << endl;
return oss.str();
}
static HtmlBuilder build(const string& root_name)
{
return {root_name};
}
};
class HtmlBuilder
{
HtmlElement root;
public:
HtmlElement build()
{
return root;
}
HtmlBuilder(const string& root_name)
{
root.name = root_name;
}
HtmlBuilder& add_child(const string& child_name, const string& child_text)
{
HtmlElement e{child_name, child_text};
root.elements.emplace_back(e);
return *this;
}
string str() const
{
return root.str();
}
};
int main(int argc, char const *argv[])
{
HtmlBuilder builder("ul");
builder.add_child("li", "apple").add_child("li", "orange");
cout << builder.str() << endl;
return 0;
}
Edit - build returns object instead of reference.
As the first comment points out you need to separate the declaration from the definition, otherwise the compiler is forced to tackle both at once, as they're given.
In your original code:
class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
public:
static HtmlBuilder build(const string& root_name)
{
return {root_name};
}
};
Here the compiler is being instructed to construct and return something it only knows by name, it knows nothing about how to create one of these. That's where you get the error. If instead you split this up and have a header file like:
// html_element.h
class HtmlBuilder;
class HtmlElement
{
friend class HtmlBuilder;
public:
static HtmlBuilder build(const string& root_name);
};
Here it's understood that something called HtmlBuilder is involved, and it's not clear what that is, but that's fine so long as it's eventually explained.
Then later in your implementation file:
#include "html_builder.h"
#include "html_element.h"
HtmlBuilder HtmlElement::build(const string& root_name)
{
return {root_name};
}
This means it doesn't need to know exactly how to make one, it just has the general idea, and by the time your implementation is addressed it's all clear because the header file has been processed.
Note that you should not return a reference to a temporary as JaMiT points out, so I've removed that from this code.
It's a good practice to split declarations (.h or .hpp as you prefer) from definitions/implementations (.cpp) to avoid traps like this. It also makes it a lot easier to find things when working with your code.

how to compare a vector of pointers and string ?

struct compare{
string k;
compare(string a) : k(a){}
bool operator()(const product* t)const{
return (t->productdetails.getName()<k);
}
};
void cashier::calculate(string s,vector<product*> &a){
//this is lambda (tried to use it ,but doesn't work)
auto comp=[](const product* t, const string b)
{
return (b < t->productdetail.getName());
};
if (std::binary_search ( a.begin(), a.end(),s, compare(s)))
cout << "found!\n";
else
std::cout << "not found.\n";
}
I'm stuck in this part for a long time.
the vector holds product(class) pointer. product pointer points to productdetail which has two variables (name and price)
I need to look up (string s) in the vector and if the string s is in vector (product->productdetail.getName()), I need to return the price..
how to compare proudct* and string s ?
my teacher gave me advice that i need to make anther string conversion function since the comparing type need to be the same..
(I tried to use lambda and it didn't work and changed to compare function)
I concur with #Fureeish, using bare pointers in modern C++ is not a good choice, unless you absolutely have to.
That said, writing predicates for the standard library requires a good knowledge of the library methods you are using. Have a look at std::binary_search documentation. A simple application is to search for the same type as you are searching through. In other words your needle is the same type as what is in your haystack. Here is an example:
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
};
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end(), productCompare);
product searchProduct{"slow cooker", 142.99};
if (std::binary_search(producList.begin(), producList.end(), searchProduct, productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}
But that lacks elegance. Your needle can be a different type, the answer is actually in this SO question. Here is a rewrite that takes advantage of this. This idiom is a bit more complicated to write but is better related to the actual problem and therefore easier to understand. Ultimately you never know which side of the compare is going to be needle and which side is going to be hay. So you have to write your compare predicate to accept both comparisons.
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(std::string const &lhs, product const &rhs) {
return lhs < rhs.productDetails.name;
}
bool operator()(product const &lhs, std::string const &rhs ) {
return lhs.productDetails.name < rhs;
}
};
// Used by std::sort
bool operator<(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end());
if (std::binary_search(producList.begin(), producList.end(), std::string("slow cooker"), productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}

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);
}