I am working with Qt 5.10 and I have to subclass QDatastream and I overload the operator << with an other class, like this :
class myDataStream:public QDataStream
{
public :
myDataStream(QIODevice* device):QDataStream(device)
{}
};
class data
{
public:
data(double v):data_(v) {}
double getData() const {return data_;}
void record(myDataStream& stream) const;
private:
double data_;
};
void data::record(myDataStream &stream) const
{
stream<<getData();
}
myDataStream &operator<<(myDataStream &stream, const data &d )
{
stream<<d.getData(); //<------ Error here
return stream;
}
I have this error :
> error: use of overloaded operator '<<' is ambiguous (with operand types 'myDataStream' and 'double')
When I remove the const operator behind data like this :
myDataStream &operator<<(myDataStream &stream, data &d )
{
stream<<d.getData();
return stream;
}
I don't have error. The operator<< doesn't change the class data ... doesn' it ? the getData() method is const.
I don't understand.
Someone to help me ?
Finaly, I will follow the KubaOber advices (in comments of my questions) and make QDataStream a composition of my class instead of subclassing QDataStream.
Thanks to KubaOber for its advices !
Related
I'm writing an application in which I need serialization to store some data in files. For serialization I want to use the QDataStream class.
I can't compile my code due to this compiler error:
Error 1 error C2679: binary '<<' : no operator found which takes a
right-hand operand of type 'const CListItem' (or there is no
acceptable conversion) c:\qt\4.8.6\src\corelib\io\qdatastream.h 265
See the relevant code below. Anyone knows what's going on here?
There is a similar question which didn't help me. When I follow the steps described there, I get this (similar) error:
Error 1 error C2678: binary '<<' : no operator found which takes a
left-hand operand of type 'QDataStream' (or there is no acceptable
conversion) c:\qt\4.8.6\src\corelib\io\qdatastream.h 265
This is my problem:
What I want to serialize is a class called CMPProject.
CMPProject holds
CListModel* m_pData;
QDateTime m_dateTimeCreated;
This is basically what should be serialized.
CMPProject has operators to stream its contents into a QDataStream.
MPProject.h:
#ifndef _MPPROJECT_
#define _MPPROJECT_
#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QDateTime>
#include "ListModel.h"
class CMPProject
{
public:
// ...
friend QDataStream& operator <<(QDataStream& stream, const CMPProject& project);
friend QDataStream& operator >>(QDataStream& stream, CMPProject& project);
private:
static const quint32 m_streamHeader = 0x1329453;
QFile* m_pFile;
CListModel* m_pData;
QDateTime m_dateTimeCreated;
};
#endif // _MPPROJECT_
The data stream operators in MPProject.cpp:
QDataStream& operator <<(QDataStream& stream, const CMPProject& project)
{
return stream << project.m_dateTimeCreated << *(project.m_pData);
}
QDataStream& operator >>(QDataStream& stream, CMPProject& project)
{
return stream >> project.m_dateTimeCreated >> *(project.m_pData);
}
m_pData is of type CListModel. CListModel contains the actual data stored as a QList<CListItem>.
To serialize the CListModel I added the according operators in ListModel.h:
#ifndef _LISTMODEL_
#define _LISTMODEL_
#include <QtCore/QAbstractListModel>
#include <QtCore/QList>
#include <QtCore/QStringList>
#include "ListItem.h"
typedef QMap<unsigned int, QString> TValueMap;
class CListModel : public QAbstractListModel
{
public:
// ...
template<typename T>
friend void operator <<(QVariant& data, const QList<T>& target);
template<typename T>
friend void operator >>(const QVariant& data, QList<T>& target);
friend QDataStream& operator <<(QDataStream& stream, const CListModel& listModel);
friend QDataStream& operator >>(QDataStream& stream, CListModel& listModel);
private:
QList<CListItem> m_items;
};
#endif // !_LISTMODEL_
and ListModel.cpp:
template<typename T>
void operator <<(QVariant& data, const QList<T>& target)
{
QVariantList list;
list.reserve(target.count());
for (int i = 0; i < target.count(); i++) {
QVariant item;
item << target[i];
list.append(item);
}
data = list;
}
template<typename T>
void operator >>(const QVariant& data, QList<T>& target)
{
QVariantList list = data.toList();
target.reserve(list.count());
for (int i = 0; i < list.count(); i++) {
T item;
list[i] >> item;
target.append(item);
}
}
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
// ERROR C2679 does not occur when I change this line to "return stream;"
return stream << listModel.m_items;
}
QDataStream& operator >>(QDataStream& stream, CListModel& listModel)
{
return stream >> listModel.m_items;
}
In order to serialize the contents of listModel.m_items (objects of type CListItem) I implemented the according operators in ListItem.h:
#ifndef _LISTITEM_
#define _LISTITEM_
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QDateTime>
#include <QtCore/QVariantMap>
class CListItem
{
public:
// ...
friend void operator <<(QVariant& data, const CListItem& target);
friend void operator >>(const QVariant& data, CListItem& target);
private:
QString m_name;
QString m_domain;
QString m_login;
QString m_password;
QDateTime m_LastModified;
};
#endif // !_LISTITEM_
and ListItem.cpp:
template<typename T>
void operator <<(QVariant& data, const T& target)
{
data = QVariant::fromValue<T>(target);
}
template<typename T>
void operator >>(const QVariant& data, T& target)
{
target = data.value<T>();
}
void operator <<(QVariant& data, const CListItem& target)
{
QVariantMap map;
map["name"] << target.m_name;
map["domain"] << target.m_domain;
map["login"] << target.m_login;
map["password"] << target.m_password;
map["dateModified"] << target.m_LastModified;
data << map;
}
void operator >>(const QVariant& data, CListItem& target)
{
QVariantMap map;
data >> map;
map["name"] >> target.m_name;
map["domain"] >> target.m_domain;
map["login"] >> target.m_login;
map["password"] >> target.m_password;
map["dateModified"] >> target.m_LastModified;
}
I fixed it.
The problem was that I didn't have operators to put my QList into a QDataStream. But I defined wrappers to store my list in QVariant, so (of course) I just should have used those.
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
QVariant var;
var << listModel.m_items;
return stream << var;
}
QDataStream& operator >>(QDataStream& stream, CListModel& listModel)
{
QVariant var;
stream >> var;
var >> listModel.m_items;
return stream;
}
It looks like here is no operator<< overloaded for arguments: QDataStream & and QList<CListItem> const&. In the reference here and here, there aren't any documented.
The second error addresses this, but there also should be QList<CListItem> argument mentioned. Was that the full error message?
Basically, you should be using this:
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
for(auto const& item : listModel.m_items)
stream << item; // write elements one by one
return stream;
}
This template might serve you for multiple types (or something akin to Pretty-print C++ STL containers):
template <typename Stream, typename Containter>
Stream& operator <<(Stream& stream, const Containter& container)
{
for(auto const& item : container)
stream << item;
return stream;
}
Your code would be valid without making change to operator<< you defined. Hope that helps.
In my project I use a class class called Message which inherits from std::ostringstream to print out human readable information of other class types.
So its << operator is overloaded several times taking my own class types which I want to print out.
class Message : public ostringstream
{
public:
Message() {};
virtual ~Message() {};
Message& operator <<(const MyTypeA &a) { return *this << a.getStr(); };
Message& operator <<(const MyTypeB &b) { return *this << b.identifier(); };
Message& operator <<(const MyTypeC &c) { return *this << c.foo(); };
// Pass everything unknown down to ostringstream, and always return a Message&
template<class T>
Message& operator <<(const T &t)
{
(std::ostringstream&)(*this) << t;
return *this;
}
};
Without the template
MyTypeA a,b;
Message m;
m << a << "-" << b;
the code would not compile, as (m << a << "-") would return a ostringstream& which would not be able to take 'b'. So I use the template to make sure to always return a Message&.
My Problem:
Message m;
m << "Hello, world" << std::endl;
generates a veeery long compiler error and I do not know why.
Here is a minimalistic "not" compilable example of my problem, and here is the corresponding compiler output.
Do not derive from any of the stream classes to create a new stream! The only reason to derive from std::ostream or std::istream is to create a stream properly set up to use a suitable stream buffer. Instead of deriving from a stream, you should derive from std::streambuf to create a new source or destination. To create output operators for new types you'd overload operator<<() with std::ostream& as first argument and your custom type as second argument. Likewise with std::istream&.
BTW, the problem you encountered is because std::endl is a function template. Trying to pass a function template somewhere requires that the appropriate instantiation can be deduced. Since your output operators don't cover a suitable signature, the instantiation of std::endl can't be deduced. I could state what's needed but that would be pointless as it is the wrong way to go anyway.
Here is how to make your code compile: http://pastebin.com/xAt5junf
The relevant excerpt:
class Message : public ostringstream
{
public:
Message() {};
virtual ~Message() {};
};
ostream& operator <<(ostream &os, const MyTypeA &a) {
return os << a.getStr();
};
ostream& operator <<(ostream &os, const MyTypeB &b) {
return os << b.getStr();
};
I have read some similar questions and answers at SO, but don't really understand the answers there. My apologies, if this is a duplicate.
Have a base class like this.
class CParam
{
public:
virtual void PrintData(ostream &OutStream) = 0;
};
Now I inherit from this:
class CUInt32:public CParam
{
public:
void PrintData(ostream &OutStream);
}
void CUInt32::PrintData(ostream &OutStream)
{
// Write some data to OutStream Here
}
I overload operator << for CUInt32 class
inline ostream &operator<<(ostream &OutStream, CUInt32 &UInt32Obj)
{
UInt32Obj.PrintData(OutStream);
return (OutStream);
}
In int main() function I do the following:
int main()
{
CParam *cp = new CUInt32(ANALOG);
cout << *cp;// Error
return 0;
}
I get an error saying
error: no match for 'operator<<' in 'std::cout << *cp'|
My questions are
Is it possible to use polymorphic base class pointers with cout?
If yes, how we could do this?
Thanks for your time!
The operator is not defined for the base class.
Simply change this:
inline ostream &operator<<(ostream &OutStream, CUInt32 &UInt32Obj)
{
UInt32Obj.PrintData(OutStream);
return (OutStream);
}
to this:
inline ostream &operator<<(ostream &OutStream, CParam& cParam)
{
cParam.PrintData(OutStream);
return (OutStream);
}
Basically, defining the PrintData in the base class as virtual/abstract ensures it will be available for all subclasses and the correct function will be called.
Along with the obvious point (operator<< should take a reference to a const base) you also want to change your definition of PrintData to make it a constmember function, so it can be invoked on a const object. The resulting code ends up something like this:
struct CParam {
virtual void PrintData(ostream &OutStream) const = 0;
};
struct CUInt32 : CParam {
void PrintData(ostream &OutStream) const {}
};
ostream &operator<<(ostream &OutStream, CParam const &UInt32Obj) {
UInt32Obj.PrintData(OutStream);
return (OutStream);
}
Since overloading code uses PrintData, you could define the function at base class level itself. Since compiler couldn't find any overloading at base class level, it throws exception.
I am trying to overload the >> operator to use it like cin with my class. Here is the code:
class Base {
public:
int mx;
Base() {}
Base(int x) : mx(x) {}
friend std::istream &operator>>(std::istream &, Base &);
friend std::ostream &operator<<(std::ostream &, const Base &);
};
std::istream &operator >>(std::istream &in, Base &object) {
in >> object.mx;
return in;
}
std::ostream &operator <<(std::ostream &out, const Base &object) {
out << object.mx;
return out;
}
int main() {
Base test();
std::cin >> test;
std::cout << test;
system("PAUSE");
return 0;
}
When I try to compile I get "error C2679: binary '>>' : no operator found which takes a right-hand operand of type 'Base (__cdecl *)(void)' (or there is no acceptable conversion)"
and Intellisense says no operator '>>' matches these operands.
the ostream version doesn't seem to have any problem.
Why?
Your code has two problems.
1) This declares a function instead of defining variable:
Base test();
Make that:
Base test;
2) You need to take a reference for the second parameter of operator>>:
std::istream &operator >>(std::istream &in, Base& object)
Also, your code does not really work for operator<<, at least it won't do what you are expecting it to do unless you fix problem 1) from above.
the way you are creating the object is wrong , should use as :
Base test;
I am trying to create my own std::string wrapper to extend its functionality.
But I got a problem when declaring the << operator.
Here's my code so far:
my custom string class:
class MyCustomString : private std::string
{
public:
std::string data;
MyCustomString() { data.assign(""); }
MyCustomString(char *value) { data.assign(value); }
void Assign(char *value) { data.assign(value); }
// ...other useful functions
std::string & operator << (const MyCustomString &src) { return this->data; }
};
the main program:
int main()
{
MyCustomString mystring("Hello");
std::cout << mystring; // error C2243: 'type cast' : conversion from 'MyCustomString *' to 'const std::basic_string<_Elem,_Traits,_Ax> &' exists, but is inaccessible
return 0;
}
I wanted cout to treat the class as a std::string, so that I won't need to do something like:
std::cout << mystring.data;
Any kind of help would be appreciated!
Thanks.
Just fyi: my IDE is Microsoft Visual C++ 2008 Express Edition.
If you look at how all stream operators are declared they are of the form:
ostream& operator<<(ostream& out, const someType& val );
Essentially you want your overloaded function to actually do the output operation and then return the new updated stream operator. What I would suggest doing is the following, note that this is a global function, not a member of your class:
ostream& operator<< (ostream& out, const MyCustomString& str )
{
return out << str.data;
}
Note that if your 'data' object was private, which basic OOP says it probably should, you can declare the above operator internally as a 'friend' function. This will allow it to access the private data variable.
You need a free-standing function (friend of your class, if you make your data private as you probably should!)
inline std::ostream & operator<<(std::ostream &o, const MyCustomString&& d)
{
return o << d.data;
}
Firstly, you seem to have an issue with the definition of MyCustomString. It inherits privately from std::string as well as containing an instance of std::string itself. I'd remove one or the other.
Assuming you are implementing a new string class and you want to be able to output it using std::cout, you'll need a cast operator to return the string data which std::cout expects:
operator const char *()
{
return this->data.c_str();
}
That's not how you overload the << operator. You need to pass in a reference to an ostream and return one (so you can stack multiple <<, like std::cout << lol << lol2).
ostream& operator << (ostream& os, const MyCustomString& s);
Then just do this:
ostream& operator << (ostream& os, const MyCustomString& s)
{
return os << s.data;
}