Class that inherits std::ostream and operator<< for QString - c++

Hell ! I'm trying to make a class that would help me with outputting text to stdout ... Anyway, everything is working, except for one thing. Let's say that I've create object of my class called out. When I do this, everything works prefectly:
out<<"test test"<<std::endl;
And it also works when I do this:
out<<QString("another string")<<std::endl;
But, when I try to chain these two thing together, like this:
out<<"test test"<<std::endl<<QString("another string")<<std::endl;
I get that super-big error, that's eventually telling me that operator<< doesn't accept parameter of type QString. That's strange, because it works OK when I don't chain QString ... Also this works:
out<<"test test"<<std::endl<<"another string"<<std::endl;
and this:
out<<QString("another string")<<std::endl<<"test test"<<std::endl;
So I guess I have problem with my operator<< function ... Either I didn't make operator<< correctly, or I don't return correct value. Or maybe something else is wrong. Anyway, I can't figure it out, so could you help me ? Bellow is source code:
output.h: http://xx77abs.pastebin.com/b9tVV0AV
output.cpp: http://xx77abs.pastebin.com/5QwtZRXc
And of course, the super-big error :D
http://xx77abs.pastebin.com/8mAGWn47
EDIT: for all you wondering, I'm not using namespaces ...

This compiles for me (with the command line from your third link):
#include <iostream>
#include <sstream>
#include <QString>
class Output: public std::ostream
{
friend std::ostream& operator<<(std::ostream &out, const QString var);
private:
class StreamBuffer: public std::stringbuf
{
private:
std::ostream &out;
QString prefix;
public:
StreamBuffer(std::ostream& str, const QString &p);
virtual int sync();
};
StreamBuffer buffer;
public:
Output(const QString &prefix);
};
Output::Output(const QString &prefix) :
std::ostream(&buffer), buffer(std::cout, prefix)
{
}
Output::StreamBuffer::StreamBuffer(std::ostream& str, const QString &p)
:out(str)
{
prefix = p + "-> ";
}
std::ostream& operator<<(std::ostream &out, const QString var)
{
out<<qPrintable(var);
return out;
}
int Output::StreamBuffer::sync()
{
out <<qPrintable(prefix)<< str();
str("");
out.flush();
return 0;
}
int main()
{
Output out (QString (">")) ;
out<<"test test"<<std::endl;
out<<QString("another string")<<std::endl;
out<<"test test"<<std::endl<<QString("another string")<<std::endl;
}
If it compiles for you too, you should be able to morph it into your failing code to find the error.

Are you using namespaces? if you are, have you defined the operator<< for QString in a specific namespace? I can't see anything wrong with the above code (except the overload should accept a const reference rather than a copy!)
EDIT: should add, if it is in a namespace, move it out, else it will not be found.
EDIT2: add the declaration of the operator<< to the header file, after your class declaration - the compiler does not know of the existence of this overload until you do.
std::ostream& operator<<(std::ostream &out, const QString& var);

I feel compelled to note that Qt provides a function/class to do exactly this, and it's called QDebug. Since you're already bound to Qt, it should not be a problem to use it.

Related

std::ostream : class is inaccesible [C++]

I am getting this error in my implementation:
struct bookdatabase::Bookdatabase::Book
class "bookdatabase::BookDatabase::Book" is inaccessible
None of the following solutions solved my problem:
std::basic_ostream is inaccessible in C++
cannot access private members in friend ostream
My ostream and istream friend function can't access private class members
member of class inaccessible
Inaccessible Members ?
Here's a picture of what visual studio has issue with in the .cpp file.
Here's a picture of the declaration in the header file.
Database.h
#include <string>
#include <vector>
#ifndef BOOKDATABASE_H
#define BOOKDATABASE_H
namespace bookdatabase {
class BookDatabase {
private:
struct Book {
private:
std::string authorFirstName, authorLastName, authorFullName, bookTitle, pubDate;
public:
Book(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
std::string getAuthor() const;
std::string getBookTitle() const;
std::string getPubDate() const;
bool operator < (const Book &rhs) const;
friend std::ostream& operator << (std::ostream& out, const bookdatabase::BookDatabase::Book& book);
};
void sortBooks();
std::vector<Book>::iterator search(const std::string &title);
public:
BookDatabase();
void printBookList();
std::vector<Book> getDatabase() const;
void removeBook(const std::string &title);
void addBook(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
private:
std::vector<Book> database;
};
}
#endif // BOOKDATABASE_H
Database.cpp
std::ostream & bookdatabase::operator<<(std::ostream & out, const bookdatabase::BookDatabase::Book & book) {
out << authorFullName << ". " << bookTitle << ". " << pubDate;
return out;
}
Am I having this issue because the Book class is a nested class?
Alright, I seem to have discovered two things here which might be the problem you're having, one of which might be a bug in Visual Studio.
1. First of all, the thing which is not a bug
user0042, in his response to your post is right, operator<< being declared as friend in the struct Book results in the operator<< only being able to access private members of Book. But it cannot access Book itself, because Book is a private member of the enclosing BookDatabase class. Therefore you have to move the friend declaration to be outside Book and in BookDatabase.
Once you do that, operator<< can now access the private data member Book of BookDatabase. Note however that this does not give permission to operator<< to access the private data members of Book itself, namely authorFirstName, authorLastName, authorFullName, bookTitle, pubDate
2A. Now for the (what I believe to be) VS2017 scope operator bug
Let's say you have moved the friend declaration to BookDatabase, you still have to define the implementation in a specific way. The following two pieces of code should be equivalent ways to define the function in a Database.cpp file, but one of them doesn't work in VS2017 15.4.5.
It's ok to do
namespace bookdatabase {
ostream& operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
}
} // OK
But not ok to do
ostream& bookdatabase::operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
} // Visual Studio cannot access book
There seems to be an issue with Visual Studio's :: operator being able to obtain the friend property of a function.
So to answer your question: if you want your << operator overload to work you need to use the first method to define it in the .cpp implementation file.
2B. In fact I wrote a simple test program to show the VS2017 friend and :: bug
namespace my_namespace {
class Test {
private:
struct Nested {};
public:
friend void func(Test::Nested&);
};
void func(Test::Nested&);
}
// DOES NOT COMPILE in VS2017 15.4.5, OK in GCC 6.3 and Clang 3.8.0
// VS2017 says Nested is inaccessible
void my_namespace::func(my_namespace::Test::Nested&) {
}
But using namespace and brackets works
namespace my_namespace {
class Test {
private:
struct Nested {};
public:
friend void func(Test::Nested&);
};
void func(Test::Nested&);
}
// changed to namespace + brackets,
// COMPILES in VS2017 15.4.5, GCC 6.3 and Clang 3.8.0
namespace my_namespace {
void func(my_namespace::Test::Nested&) {
}
}
Can someone please independently verify this?
I also posted a bug report on the Microsoft Developer Community
My answer for most operator << woes is to declare a member print() method that does the hard work and call it from operator <<.
Usually I am happy for the print method to be public, and get rid of all the friend nastiness.

Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.
Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.
Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.
The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.
#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

Error C2679 while trying to serialize QList of custom class with QDatastream

I got a custom class Foo:
class Foo
{
public:
// getters and setters
// ...
private:
QString string;
QStringList list;
int number;
}
The serialization of Foo has worked as expected:
QDataStream &operator<<(QDataStream &stream, const Foo &foo)
{
stream<<foo.getString()<<foo.getList()<<foo.getNumber();
return stream;
}
but when I attempted to serialize QList<Foo>, I got
error C2679: binary '<<' : no operator found which takes a right-hand operand of type “const Foo”
which directed to the corresponding Qt code (qdatastream.h):
template <typename T>
QDataStream& operator<<(QDataStream& s, const QList<T>& l)
{
s << quint32(l.size());
for (int i = 0; i < l.size(); ++i)
s << l.at(i); // <--- compiler error here
return s;
}
I know QList<T>::at() returns const T &, but I have no idea why it should fail to compile here. Please point out my error, I'd like to know how to fix this. Also, if I miss the necessary parts of code please do let me know. Thanks!
[Edit]:
For reference, my environment is Qt 4.8.5 with MSVC2010/ Win 7 and I am using Qt creator.
Besides, this is how I serialize QList<Foo>:
QFile file("file.dat");
file.open(QIODevice::ReadWrite);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8);
out<<fooList; // It's the instant of QList<Foo> and it's not a pointer
//^^^^^^^^^^ compiler errors occurs as this line is added
[Last Edit]:
I finally figure out what's going on:
The operator overload that I defined to serialize Foo is written in a seperate .cpp file, where
QDataStream &operator<<(QDataStream &stream, const Foo &foo)
{
stream<<foo.getString()<<foo.getList()<<foo.getNumber();
return stream;
}
is inside foo.cpp.
The above code can be compiled but now I realize that it will never be used!
The serialization of QList<Foo> is implemented in another file notFoo.cpp, which is a "bigger class".
As I compile notFoo.cpp, only the definition and methods inside the header qdatastream.h could be found hence the error C2679 comes out, where:
template <typename T>
QDataStream& operator<<(QDataStream& s, const QList<T>& l)
{
s << quint32(l.size());
for (int i = 0; i < l.size(); ++i)
s << l.at(i); // <--- compiler error here
return s;
}
It shows that compiler doesn't know how to further serialze type Foo.
binary '<<' : no operator found which takes a right-hand operand of type “const Foo”
which means << of s << l.at(i); is not found (since I defined it in another .cpp file)
After I move the serialization method from Foo.cpp to notFoo.cpp, the code can finally be compiled.
[Conclusion]:
The compiler didn't find the function signature in the Foo.h since I define the stream operator inline within Foo.cpp.
You need to declare the stream operator in the same header where you declare the serialized type:
// Foo.h
#include <QString>
#include <QDataStream>
class Foo
{
public:
// getters and setters
// ...
private:
QString string;
QStringList list;
int number;
};
QDataStream &operator<<(QDataStream &stream, const Foo &foo);
Usually, the operator's implementation will be in the file where you implement Foo, but it could be in any .cpp file, really:
// Foo.cpp
Foo::Foo() {
...
}
...
QDataStream &operator<<(QDataStream &stream, const Foo &foo)
{
stream<<foo.getString()<<foo.getList()<<foo.getNumber();
return stream;
}

C++ overloading operator<<

I'm trying to overload the << operator for a class to emulate toString() in Java. I have a NumExpr class, and has private variable number that I want to output. so here they are:
NumExpr::NumExpr( string n ) {
number = atoi( n.c_str() );
}
string NumExpr::name() {
return "num";
}
ostream & operator<<(ostream &s, const NumExpr &num) {
s << num.number;
return s;
}
I made it a friend function so it can access the private variable
class NumExpr : public Expr {
public:
NumExpr( string v );
string name();
private:
int number;
friend ostream& operator<<(ostream &s, const NumExpr &num);
};
However I'm getting this error
./ast/Expr.cpp: In function ?std::ostream& operator<<(std::ostream&, const NumExpr&)?:
./ast/Expr.cpp:50: error: no match for ?operator<NumExpr::number?
./ast/Expr.cpp:49: note: candidates are: std::ostream& operator<<(std::ostream&, const NumExpr&)
I have searched for this error, people seem to be having the same problems but mine seems to look like the solutions people are giving out. Is there something fundamentally wrong that I'm doing or is there some syntax shenanigans that I'm not aware of?
Thanks for the help!
Okay here it is, little bit of playing around I can reproduce your problem:
The problem is that You forgot to include iostream header file.
Add:
#include<iostream>
and it should just work fine :)
EDIT:
As #James Kanze correctly suggests in comments, it is sufficient to include
#include<istream>
because you don't need everything from the iostream really.
The downside of including iostream inside of istream is little increase in compilation time.
On this page:
http://www.cplusplus.com/forum/beginner/13164/
It says to have the friend function like this:
friend std::ostream& operator<< (std::ostream&, const NumExpr&); <-
so no variable decleration. just
const NumExpr
any help?

How can I make an ostream reference an ofstream? (C++)

I'm trying to make a simple logger class, and I want the ability to either log to either a generic ostream (cout/cerr) or a file. The design I have in mind is to allow the constructor to either take an ostream& or a filename, and in the latter case create an ofstream& and assign that to the class' private ostream& like so:
class Log {
private:
std::ostream& os;
public:
Log(std::ostream& os = std::cout): os(os) { }
Log(std::string filename) {
std::ofstream ofs(filename);
if (!ofs.is_open())
// do errorry things
os = ofs;
}
};
Doing such gives me an error that ofstream's assignment operator is private. Looking over that again, it occurred to me that making a reference to a local object probably wouldn't work, and making os a pointer to an ostream and declaring and deleting it on the heap worked with the ofstream case, though not with the ostream case, where the ostream already exists and is just being referenced by os (because the only place to delete os would be in the constructor, and I don't know of a way to determine whether or not os is pointing to an ofstream created on the heap or not).
So how can I make this work, i.e. make os reference an ofstream initialized with a filename in the constructor?
For one thing, you can't rebind references once they're created, you can only initialise them. You might think you could do this:
Log(std::string filename) : os(std::ofstream(filename)) {
if (!os.is_open())
// do errorry things
}
But that's no good because you are making os refer to a temporary variable.
When you need a reference that has to be optional, that is, it needs to refer to something sometimes and not other times, what you really need is a pointer:
class Log {
private:
std::ostream* os;
bool dynamic;
public:
Log(std::ostream& os = std::cout): os(&os), dynamic(false) { }
Log(std::string filename) : dynamic(true) {
std::ofstream* ofs = new std::ofstream(filename);
if (!ofs->is_open())
// do errorry things and deallocate ofs if necessary
os = ofs;
}
~Log() { if (dynamic) delete os; }
};
The above example is just to show you what is going on, but you probably will want to manage it with a smart pointer. As Ben Voigt points out, there are a lot of gotchas that will cause unforeseen and undesired behaviour in your program; for example, when you try to make a copy of the above class, it will hit the fan. Here is an example of the above using smart pointers:
class Log {
private:
std::unique_ptr<std::ostream, std::function<void(std::ostream*)>> os;
public:
Log(std::ostream& os = std::cout): os(&os, [](ostream*){}) { }
Log(std::string filename) : os(new std::ofstream(filename), std::default_delete<std::ostream>()) {
if (!dynamic_cast<std::ofstream&>(*os).is_open())
// do errorry things and don't have to deallocate os
}
};
The unusual os(&os, [](ostream*){}) makes the pointer point to the given ostream& but do nothing when it goes out of scope; it gives it a deleter function that does nothing. You can do this without lambdas too, it's just easier for this example.
The simplest thing to do is just bind your reference to an ofstream, and make sure the ofstream lives as long as your object:
class Log
{
std::ofstream byname;
std::ostream& os;
public:
Log(std::ostream& stream = std::cout) : byname(), os(stream) { }
Log(std::string filename) : byname(filename), os(this->byname)
{
if (!os)
// handle errors
}
};
Exception safe, can't leak, and the compiler-generated special member functions are sane.
In my Log/Debug class I find it useful to create a static member variable:
class debug {
public:
...
// Overload operator() for printing values.
template<class Type1>
inline debug&
operator()(const std::string& name1,
const Type1& value1)
{
// Prettify the name/value someway in another inline function.
_stream << print_value(name1, value1) << std::endl;
return *this;
}
private:
...
static std::ostream& _stream;
};
And then in my debug.cc file:
std::ostream& debug::_stream = std::cerr;
You have to initialize the os in the initialize list in the constructors, just as what you did in Log(std::ostream& os = std::cout): os_(os) { }, because os is a reference, which can not be assigned after initialized.