Passing const QByteArray to overloaded function - c++

I have following overloaded function
void testFun(QByteArray& arr){
QTextStream out(stdout);
out << "QByte" << endl;
}
void testFun(QString str){
QTextStream out(stdout);
out << "QStr" << endl;
}
Why function void testFun(QString str) is called if I use const QByteArray as argument.
It means - this block of code:
QByteArray bA("aaa");
const QByteArray bB(bA);
testFun(bA);
testFun(bB);
gives following output:
QByte
QStr

Since the first overload takes a non-const QByteArray, it does not get used.
C++ has a feature called Converting Constructors. This means that a single-argument constructor that is not marked as explicit can be used automatically to convert one type into another for function overload resolution.
QString has such a constructor that takes a const QByteArray&. Therefore, when selecting what function overload to use, the compiler can first convert the QByteArray to a QString using that constructor, and then proceed to pass that QString into your second function.
Please see http://en.cppreference.com/w/cpp/language/overload_resolution for more information.

The underlying cause is that Qt (and by extension: you!) allows writing non-typesafe code: there's an implicit conversion from QByteArray to QString. Define QT_RESTRICTED_CAST_FROM_ASCII project-wide, wipe the build folder and rebuild the project. The call that uses the const object won't compile then, and you'll have to fix the function signatures: you should have been taking const references all along.
void testFun(const QByteArray &arr){
QTextStream out(stdout);
out << "QByte" << endl;
}
void testFun(const QString &str) {
QTextStream out(stdout);
out << "QStr" << endl;
}

Related

Can`t overload the operator << for a my own class

I am trying to reduce code redundancy using the overload of an output operator to a stream instead of print functions.
//***.h
class MainWind : public QWidget
{
Q_OBJECT
public:
explicit MainWind(QWidget *parent = nullptr);
~MainWind();
MainWind *operator<<(const QString &str);
private:
Ui::MainWind *ui;
};
//***.cpp
MainWind *MainWind::operator<<(const QString &str)
{
ui->serverConsole->insertPlainText(str);
return this;
}
At this moment everything compiles successfully.
But when I try to use:
//other.cpp
MainWind *mainWind = new MainWind;
mainWind << QString("str");
I got this error:
ServerSocket.cpp:39: error: invalid operands to binary expression
('MainWind *' and 'QString')
qstring.h:1410: candidate function not viable: no known conversion from >'MainWind *' to 'QDataStream &' for 1st argument
...
And there are a lot of candidates for this position)
Or
//other.cpp
MainWind *mainWind = new MainWind;
mainWind <<"str";
I got this error:
ServerSocket.cpp:39: error: invalid operands to binary expression
('MainWind *' and 'const char [4]') ServerSocket.cpp:39: error:
invalid operands of types 'MainWind*' and 'const char [4]' to binary
'operator<<'
CurrentSession::inst().mainWind() << "str";
^
What could be the problem?
ADDITION TO THIS QUESTION:
Attempt to use:
//*.h
friend MainWind *operator<<(MainWind *out,QString &str);
//***.cpp
MainWind * operator<<(MainWind *out, QString &str)
{
out->ui->serverConsole->insertPlainText(str);
return out;
}
Compilation of previous code is successful.
According to the idea, if the first operand could not be a pointer, this code would not compile...
But when using this:
//other.cpp
MainWind *mW = new MainWind;
mW << "str";
Compilation go to error:
ServerSocket.cpp:37: error: invalid operands of types 'MainWind*' and 'const char [4]' to binary 'operator<<'
mW << "str";
^
You need to use *mainWind << QString("str");. The LHS has to be an object, not a pointer.
While at it, I strongly recommend changing the operator<< function to return a reference to the object, not a pointer.
MainWind& operator<<(const QString &str);
and the implementation to
MainWind& MainWind::operator<<(const QString &str)
{
ui->serverConsole->insertPlainText(str);
return *this;
}
That will allow you to chain the operator.
*mainWind << QString("str") << QString("Second string");
You overloaded << on MainWnd not MainWnd*.
*mainWind << QString("str");
Also you want QString const&
//other.cpp
MainWind *mainWind = new MainWind;
mainWind <<"str";
The reason is that mainWind << "str" looks for an operator<<() that accepts two arguments, the first of which is a MainWind *.
Whereas, you have defined a MainWind::operator<<() which is called with the first argument a MainWind &. There is no direct conversion from a MainWind * to a MainWind & (or to a MainWind). Hence the error message.
One way to get the code to compile is to change mainWind <<"str" to *mainWind << "str". The * dereferences the pointer, and produces a reference, which is what your operator<<() expects.
The catch is then that
*mainWind << "str" << "another str";
will not compile, since it is equivalent to
(*mainWind).operator<<("str") << "another str";
where (*mainWind).operator<<("str") returns a MainWind *. This causes the same problem (again) when trying to stream "another str".
The real fix is to change operator<<() so it returns a reference
// within the class definition of MainWind
MainWind &operator<<(const QString &str);
// definition of the operator<<()
MainWind &MainWind::operator<<(const QString &str)
{
ui->serverConsole->insertPlainText(str);
return *this;
}
and change the calling code to either
//other.cpp version 2
MainWind *mainWind = new MainWind;
*mainWind <<"str";
// this will work too
*mainWind << "str" << "another str";
// note reliance on cleaning up mainWind to avoid a memory leak
delete mainWind;
There is no other fix that would allow you to use mainWind << "str" since overloading non-member operator<<() is only permitted on class or enumerated types, not on pointers.

How to overload an in-place and a copying string manipulation functions?

I would like to be able to do the following:
std::cout << str_manip("string to manipulate");
as well as
std::string str;
str_manip(str);
std::cout << str;
For this, I have two functions
#include <string>
// copying
std::string str_manip(std::string str)
{
// manipulate str
return str;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
but they produce the following error:
error: call of overloaded 'str_manip(std::__cxx11::string&)' is ambiguous
How can I overcome this?
The problem is with this call:
std::string str;
str_manip(str);
std::cout << str;
The compiler doesn't know which version of str_manip to call.
You can change your functions to look like this:
#include <string>
// copying
std::string str_manip(const std::string& str)
{
std::string dup = str;
// manipulate dup
return dup;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
Now, the compiler knows that the ambiguous call has to be the function that takes the non-const parameter. You can also be sure that your call that returns a std::string to the << operator isn't modifying your string.
This might be not the thing you are looking for, but for your code
std::cout << str_manip("string to manipulate");
the parameter to str_manip is not a string but const char* (actually an array, but convertible to a char pointer). You can overload based on that.
std::string str_manip(const char* s)
{
std::string str(s); // create str
// manipulate str
return str;
}
However, let's look at the big picture. When you see str_manip in your code, does this mean "change the string" or "make a new string based on the given string"? Do you want to be intentionally ambivalent on the real meaning?
Consider yourself reading your code in 1 year in future. What will you think when you see a call to str_manip - does this mutate its parameter? Does the answer to the previous question depend on context?
The goal in writing code is to make it clear, especially in a multi-paradigm language like C++. So, in my opinion, just don't do overloading that you are thinking about. Instead, make 2 distinct names, like
void frobnicate_str(std::string&) {...}
std::string get_frobnicated_str(std::string) {...}

QT ofstream use variable as a path name

I'm trying to make a function which takes QString as well as an int.
Convert QString variable into a filename for ofstream, then take the integer and place it into the file. So far I have managed to take a constant filename such as "Filename.dat" and write a variable into it. However when I try to use QString like this :
void write(const char what,int a){
std::ofstream writefile;
writefile.open("bin\\" + what);
writefile << a;
writefile.close();
}
I get an error
void write(const char,int)': cannot convert argument 1 from 'const char [5]' to 'const char
This is the function which calls write();
void Server::on_dial_valueChanged(int value)
{
write("dial.dat",value);
}
When I use "bin\dial.dat" instead of combining "bin\" with a string it works fine. ofstream.open(); uses "const char*".
I've tried all the filetypes so they may not match my description
The question is-
Does anybody have an idea how to combine "bin\" and a QString and make it work with ofstream?
I've spend a lot of time googling it but still can't make it work.
Thanks!
Any suggestions are more than welcome
void write(const char what,int a) is wrong as you pass only one char to function you should have void write(const char* what,int a) to pass pointer to cstring beginning.
You also want to concat two cstrings and in c++ you can't do it like in other languages but you can use std::string to do what you want.
Try this
#include <string>
void write(const char* what,int a){
std::ofstream writefile;
std::string fileName("bin\\");
fileName+=what;
writefile.open(fileName.c_str());
writefile << a;
writefile.close();
}

Operator << for QString

It makes sense to implement << for QString like:
std::ostream& operator <<(std::ostream &stream,const QString &str)
{
stream << str.toAscii().constData(); //or: stream << str.toStdString(); //??
return stream;
}
instead of writing
stream << str.toAscii().constData();
every time in the code.
However, since it is not in standard Qt library, I'm assuming there is any particular reason not to do so. What are the risks/inconvenience of overloading << as specified above?
If the << operator is included in the Qt library every client of the library will have to use the exact same implementation. But due to the nature of QString it is far from obvious this is what these clients want. Some people writing software interacting with legacy file in western europe may want to use Latin1() characters, US people may go with Ascii() and more modern software may want to use Utf8().
Having a single implementation in the library would restrict unacceptably what can be done with the whole library.
It's not necessary to implement such thing, as long as there exists a convenient solution like this one, involving QTextStream
QString s;
QTextStream out(&s);
out << "Text 1";
out << "Text 2";
out << "And so on....";
QTextStream is quite powerfull...
The accepted answer points out some valid reasons for why there is no operator<< function for QString.
One can easily overcome those reasons by providing some convenience functions and maintaining some state in an application specific namespace.
#include <iostream>
#include <QString>
namespace MyApp
{
typedef char const* (*QStringInsertFunction)(QString const& s);
char const* use_toAscii(QString const& s)
{
return s.toAscii().constData();
}
char const* use_toUtf8(QString const& s)
{
return s.toUtf8().constData();
}
char const* use_toLatin1(QString const& s)
{
return s.toLatin1().constData();
}
// Default function to use to insert a QString.
QStringInsertFunction insertFunction = use_toAscii;
std::ostream& operator<<(std::ostream& out, QStringInsertFunction fun)
{
insertFunction = fun;
return out;
}
std::ostream& operator<<(std::ostream& out, QString const& s)
{
return out << insertFunction(s);
}
};
int main()
{
using namespace MyApp;
QString testQ("test-string");
std::cout << use_toAscii << testQ << std::endl;
std::cout << use_toUtf8 << testQ << std::endl;
std::cout << use_toLatin1 << testQ << std::endl;
return 0;
}
Output:
test-string
test-string
test-string
I don't think there is any particular reason for excluding (nor including) this in the Qt library. Only problem that could possibly appear here is a possibility that std::ostream object could modify the contents of the parameter passed to std::ostream::operator<< function.
However, in the reference it is clearly stated that this function will modify the parameter if string buffer is passed - there is nothing about the other types, so I guess (and the common-sense is telling me) that operator<< will not modify char* parameter. Also, on this page there is nothing about modifying the passed object.
Last thing: instead of using QString::toAscii().constData(), you could use QString::toStdString() or qPrintable(const QString&) macro.

How to make an ambiguous call distinct in C++?

void outputString(const string &ss) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
int main(void) {
//! outputString("ambigiousmethod");
const string constStr = "ambigiousmethod2";
//! outputString(constStr);
} ///:~
How to make distinct call?
EDIT: This piece of code could be compiled with g++ and MSVC.
thanks.
C++ does not allow you to overload functions where the only difference in the function signature is that one takes an object and another takes reference to an object. So something like:
void foo(int);
and
void foo(int&);
is not allowed.
You need to change the number and/or the type of the parameter.
In your case the function that accepts a reference, you can make it accept a pointer, if you want to allow the function to change its argument.
You could change the signature of one of the methods. It may not look pretty, however it is the simplest way.
So you could in principle have
void outputString(const string &ss, int notneeded) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
and when you want to call the first function just call it with:
outputString("ambigiousmethod", 0);
which will result in a distinguishing call.
There is no other way (I'd love to be proven wrong on this one) since C++ does not allow overloading where passing (by value or by reference) is the only difference in signature.
Edit: as pointed out by bzabhi, you could also change the signature by changing the reference to a pointer. In the example you gave that would work, however you may have to change function code on some occasions.
According to your code, u need only
void outputString(const string &ss).
Because both methods cannot change the argument to the caller (because it's const reference or by-value passing).
Why do you need those 2 methods?
I recommend using the techinque of giving each and every function a unique name., i.e., do not use syntax overloading. I have been using it for years and I've only found advantages in it.