operator<< and std::stringstream reference? - c++

I have a class that holds a reference to a stringstream (used as an overall application log). How do I add text to the referenced stringstream?
An example (as I cannot post actual source here...)
main
stringstream appLog;
RandomClass myClass;
.....
myClass.storeLog(&applog);
myClass.addText("Hello World");
cout << appLog.str().c_str() << endl;
RandomClass cpp
void RandomClass::storeLog(stringstream *appLog)
{
m_refLog = appLog;
}
void RandomClass::addText(const char text[])
{
m_refLog << text; //help here...?
}
I'm getting the following error in my real app using a very similar setup and method structure as above.
error C2296: '<<' : illegal, left operand has type 'std::stringstream *'
error C2297: '<<' : illegal, right operand has type 'const char [11]'
I know the error is because i'm using a reference and still trying to do '<<', but how else am I to do it? m_refLog-><<???

De-reference the pointer first
void RandomClass::addText(const char text[])
{
if ( m_refLog != NULL )
(*m_refLog) << text;
}
In the constructor, initialize the member pointer to stringstream with NULL
RandomClass::RandomClass() : m_refLog(NULL)
{
...
}

It looks like your m_refLog member is a StringStream * (i.e. a pointer-to-StringStream), not a StringStream (or a StringStream &. That is the source of your compile errors.

You have a pointer, not a reference. Dereference it to obtain the stream itself.
(Recall that ptr->foo() is equivalent to (*ptr).foo().)
I'd also recommend that your functions accept const std::string& instead of pointers to C-style char buffers.
And the .c_str() in your example is redundant.
void RandomClass::addText(const std::string& text) {
(*m_refLog) << text;
}

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.

Sending a string variable as a parameter to open a file

In main:
void HandleAction(const RandomWriter & rw, string choice)
{
if(choice == "P")
{
string fileInput;
cout << "Change input file: " << endl;
cin >> fileInput;
rw.SetFilename(fileInput);
}
}
In a RandomWriter class:
void RandomWriter::SetFilename(string filename)
{
string text = GetFullFile(filename);
if (text != "")
{
fullText = text;
this->filename = filename;
}
/
Why am i getting this error when i try to pass fileInput as a parameter to SetFileName?
Thanks in advance guys!
||=== error: passing 'const RandomWriter' as 'this' argument of 'void RandomWriter::SetFilename(std::string)' discards qualifiers [-fpermissive]|
In the HandleAction function you say that the rw is a reference to a constant RandomWriter object. Then you try to call a member function on the rw object that tries to modify the constant object. That is of course not allowed, you can't modify constant objects.
So the simple solution is to remove the const part of the argument specification:
void HandleAction(RandomWriter & rw, string choice) { ... }
// ^^^^^^^^^^^^^^^^^
// Note: No longer constant
On a related note, you should probably use references to constant objects for the strings though, no need to copy them all the time.
Your RandomWriter parameter rw is declared const in your HandleAction() method, and is thus immutable and unable to be changed by your call to SetFilename().

Converting std::string to const char*, getting errors

#include <iostream>
#include <sstream>
template <typename T>
const char* numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.c_str();
}
int main() {
printf(numberToString(123));
return 0;
}
My error:
1>d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(8): error C2039: 'c_str' : is not a member of 'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>'
1> d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(26) : see reference to function template instantiation 'const char *numberToString<int>(T)' being compiled
1> with
1> [
1> T=int
1> ]
Why doesn't this work?
c_str is a member of std::string, not ostringstream. If you want to get a string out of the stream, use str(). Note, however, that returning a const char* from that string is wrong - the string will go out of scope before you can use the const char*. Therefore, have your function return a string (or have it get a buffer to write to):
template <typename T>
std::string numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.str();
}
c_str() does not exist for std::ostringstream. What you meant was:
template <typename T>
const char* numberToString(T number)
{
std::ostringstream ss;
ss << number;
return ss.str().c_str();
}
After you make that change, you will have another problem: you will be returning a pointer to a buffer that was just destroyed. To fix that, you should return a std::string:
template <typename T>
std::string numberToString(T number)
{
std::ostringstream ss;
ss << number;
return ss.str();
}
Which you can do with std::to_string already, so it is really pointless to write your own function.
That's because c_str() is the member function of std::string which returns a const char*.
To get the underlying string of a strinstream, you must use str().
The error was pretty much self explanatory:
error C2039: 'c_str' : is not a member of 'std::basic_ostringstream
Note however that you're returning a pointer to something (the underlying data of the temporary string returned by str()) that will not exist after the return statement (i.e. in the calling code) and that manipulating that pointer will quite sureley end up in undefined behavior.
As you are in C++, you could rather return the std::string directly, and output it with
std::cout << numberToString(123);
which would be safer.
You want to do:
template <typename T>
std::string numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.str();
}
int main() {
std::cout << numberToString(123);
return 0;
}
To get the underlying std::string in std::ostringstream, and then the resulting c-style string in std::string. As others have pointed out, the pointer returned by c_str goes out of scope, and therefore you must copy it to a buffer or to another std::string. If you insist on using printf, then use c_str on the function call:
printf("%s", numberToString(123).c_str());
For more information, see Is it a good idea to return " const char * " from a function?
Depending on what somestlstring is and what is being done there.
If it is a local variable you are returning a pointer into memory that
is being released when GetSomeString completes, so it is a dangling
pointer and an error.
It all boils down to the lifetime of somestlstring and the operations
you perform on it. The pointer returned by .c_str() is guaranteed to
be valid only up to the next mutating operation in the string. So if
something changes somestlstring from the call to .c_str() and before s
is constructed you will be in undefined behavior land.
However, you can simply use std::to_string.
std::string s = std::to_string(123);

How do I pass a string into a function?

I am attempting to use an overloaded function to get a string.
void get(char prompt[], int size,const std::string b = "")
{
std::cout << prompt << ": ";
std::cin.get(b, size);
std::cin.ignore(10, '\n');
}
Now I did just change the last argument from a character array to a string at the advice of another poster on this site, so I'm a little lost. I'm getting error message at the '.' in between cin and get. I've also tried cin.getline (I have no idea if there's a difference or what it is)
Error message : cannot convert parameter 1 from 'const std::string' to
'char *'
The error has a lot of other stuff, but I think that's the important bit.
I'm indirectly answering your question by suggesting an alternative method. Here's my implementation, along with an example of how to use it.
#include <string>
#include <iostream>
#include <ostream>
std::string get(std::string const& prompt)
{
std::string ret;
std::cout << prompt << ": ";
getline(std::cin, ret);
return ret;
}
int main()
{
std::cout << get("Please enter your answer") << std::endl;
// or
std::string prompt("Enter your answer");
std::string response = get(prompt);
std::cout << response << std::endl;
}
When working with strings, you need to use the free function getline from the string header, not the member function getline from iostream. So it would be std::getline(std::cin, b);.
That being said getline won't accept a const string as its argument for the simple reason that the whole point of calling getline is to write to the string. Also note that unless you make b a (non-const) reference, any changes you perform on b inside your get method will not be visible outside of the method since strings are copied if you pass them by value.
The difference between istream::get(char*, streamsize) and istream::getline(char*, streamsize) is that the latter discards the newline character (as does the getline method for strings) while the former does not.
http://www.cplusplus.com/reference/iostream/istream/get/
http://www.cplusplus.com/reference/iostream/istream/ignore/
your call to get() doesn't match any of the existing istream methods. it just may end up being recursive if it ever works?
#include <string>
namespace std {
//I am attempting to use an overloaded function to get a string.
class Ciostream : public iostream {
public:
void get(char prompt[], int size,const std::string b = "")
{
cout << prompt << ": ";
cin.get(b, size);
cin.ignore(10, '\n');
}
};
}
//1.cpp:11:28: error: no matching function for call to 'std::basic_istream<char>::get(const string&, int&)'

error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)

I am really confused on why I am getting following compilation error.
Microsoft Visual Studio Compiler.
error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <iterator>
class MyException {
public:
MyException( std::string message,
int line = 0) : m_message(message),
m_line(line) {}
const char* what() const throw(){
if ( m_line != 0 ) {
std::ostringstream custom_message;
custom_message << "Parsing Error occured at ";
custom_message << m_line << " Line : ";
custom_message << m_message;
m_message = custom_message.str();
}
return m_message.c_str();
}
private:
std::string m_message;
int m_line;
};
int main(int argc, char **argv) {
try {
// do something
}catch(MyException &e){
std::cout << e.what();
}
}
Error is coming at line
m_message = custom_message.str();
You declare the method as const
const char* what() const throw(){
but then you try to change the object
m_message = custom_message.str();
so you get an error.
What you should do instead is construct the custom message in the constructor.
class MyException {
public:
MyException(const std::string& message, int line = 0) :
m_message(message), m_line(line) {
if ( m_line != 0 ) {
std::ostringstream custom_message;
custom_message << "Parsing Error occured at ";
custom_message << m_line << " Line : ";
custom_message << m_message;
m_message = custom_message.str();
}
}
const char* what() const throw(){
return m_message.c_str();
}
private:
std::string m_message;
int m_line;
};
Also I changed your code to pass the std::string by reference, which is usual practice.
You are trying to assign to MyException::m_message inside a const-qualified method MyException::what(). Inside such what() the entire *this object is considered to be const, which means that m_message member is also const. You can't assign anything to a const-qualified std::string object, since std::string's assignment operator requires a modifiable (i.e. a non-const one) object on the left-hand side. You are supplying a const one.
If you really want to be able to modify the m_message inside what(), you should declare it as mutable member of the class (in this case it appears to be a good idea). Or use some other approach.
As #john noted, in your specific case it makes more sense to actually build m_message in constructor instead of postponing it till what(). I don't really understand why you'd even want to rebuild your m_message every time you call what(). Unless your m_line is expected to change somehow from one call to what() to another, there's really no need to do it every time.
In addition to the other answers;
You're not including the <string> header, which may be the cause of a problem later.
Something that used to get me a lot is that some std:: headers include others, which allows you to use a class, but maybe only with limited functionality because the std:: headers that they include are the bare minimum that is needed for that file to run. This is quite an annoyance because sometimes you declare a std:: class such as string and you haven't included the header, the definition will be fine but everything else may or may not work - leading you to a lot of debugging because the definition worked fine.
See the declaration of the what() function, it is marked const (the second const on the line). That means that it cannot alter any member variables, in your case the m_message string. That is why you get the error.
Now, how do you fix it?
Your code is wrong, your what() function will prepend the "Parsing Error occured at " etc. text each time you invoke the what() function. So, instead of doing that having to modify the m_message member, I suggest that you format the entire message in the ctor of the class:
MyException(std::string message, int line = 0)
{
if (line != 0)
{
std::ostringstream custom_message;
custom_message << "Parsing Error occured at ";
custom_message << line << " Line : ";
custom_message << message;
m_message = custom_message.str();
}
else
m_message = message;
}