I am trying to create a method that will accept a stream (i.e. ostringstream) parameter that will be logged to a file.
In the header file, it is declared as:
static void Log(const std::ostringstream& message, LoggingSeverity severity = LoggingSeverity::info);
However, when I try to call the method from another class, such as:
SimpleLogger::Log("Name registered.", SimpleLogger::LoggingSeverity::trace);
I am getting the following error: E0415 no suitable constructor exists to convert from "const char []" to "std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char>>"
And if I try to structure a call by concatenating strings (input is of type std::string), like this:
SimpleLogger::Log("String to int conversion of [" << input << "] failed.", SimpleLogger::LoggingSeverity::warning);
I receive the following error: E0349 no operator "<<" matches these operands
From the errors, I understand that the std::ostringstream parameter doesn't like the strings, but I was under the impression that the data type would provide me the needed functionality of being able to provide objects to the stream, including, for example, int values. Is there a better data type to achieve the desired result? Or, is the structured calls to the method incorrect?
Well the problem here is you are passing a string to a stringstram constructor, the idea is ok but the constructor is defined explicit so there is no automatic conversion to from string to stringstream, explicit stringstream (const string& str , ios_base::openmode which = ios_base::in | ios_base::out); , you can find details here
As for your question here is a sample code,
#include <string>
#include <iostream>
#include <sstream>
void Logg(const std::ostringstream& message) {
std::cout<<message.str()<<std::endl;
}
int main()
{
std::string a= "other message";
Logg(std::ostringstream("some message"));
Logg(std::ostringstream(a));
Logg(static_cast<std::ostringstream>(a));
}
Output
some message
other message
other message
Related
I have opened a file to write to, and according to some conditions sometimes I want to print output to the screen and sometimes to the file. So I edited my function to be like this:
Cacl(const std::string &str, const ofstream &to=std::cout)
But I'm getting an error, what may cause this?
no viable conversion from 'std::__1::ostream' (aka 'basic_ostream<char>') to 'const std::__1::ofstream' (aka 'const basic_ofstream<char>')
void Calculator::solve(const std::string &command, const ofstream &to=std::cout) {
std::cout is an object of type std::ostream which is a base class of std::ofstream (it's more general than std::ofstream), so you could just do:
void Calculator::solve(const std::string &str, std::ostream &to = std::cout) {
// instead of ofstream ^^^^^^^
and now you can pass an ofstream object to this function as well.
Also, the ostream shouldn't be const otherwise you won't be able to write to it.
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) {...}
For a project, I'd like to use stringstream to carry on data. To achieve this goal, I have to pass some stringstream as parameter to some function, but when I output the stringstreams, I see something like an address.
The code :
#include <iostream>
#include <sstream>
void doStuff(const std::iostream& msg)
{
std::cerr << msg << std::endl;
}
int main(void)
{
doStuff(std::stringstream("av"));
}
The output is :
0xbff4eb40
Can someone explains why I get an address when passing an rvalue ?
And why can't I pass a stringstream by value ?
You probably want to access the string on which the stringstream is storing its data:
void doStuff(const std::stringstream& msg)
{
std::cerr << msg.str() << std::endl;
}
What is happening in your code is that iostreams contain a void* operator which returns 0 if the stream contains any error or has reached EOF, and another value otherwise. This is usefull for error checking.
When you try to write you stream to std::cerr, the compiler realizes that the stream can be converted to a void* using that operator, and that a void* can be written to a ostream(the operator<< has been defined), and therefore uses it.
Note that i changed the method's signature so that it receives an std::stringstream as an argument, since std::iostream::str is not defined(this method is only available on string streams).
You get an address because it (like other streams) has a conversion to void * (which is primarily useful as a Boolean, to see whether reading/writing the stream has failed).
You can't pass it by value, because streams (again, in general, not just stringstreams) don't support copying and/or assigning.
To print the content of the stream, you could do something like:
void dostuff(std::iostream &msg) {
std::cerr << msg.rdbuf() << "\n";
}
Edit: Here's a complete demo program:
#include <iostream>
#include <sstream>
void show(std::ostream &os) {
std::cout << os.rdbuf() << "\n";
}
int main(){
std::stringstream test("whatever");
show(test);
return 0;
}
When I execute it, the output I get is the expected "whatever".
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;
}
After reading Jerry Coffin's answer on this question I copy-pasted his code into my editor, and after some minor edits it compiled and run like it should.
Here is the code after the changes:
#include <iostream>
#include <string>
#include <istream>
#include <fstream>
class non_blank {
private:
std::string data_;
friend std::istream& operator>> (std::istream &is, non_blank &n) {
std::getline(is, n.data_);
if (n.data_.length() == 0) {
is.setstate(std::ios::failbit);
}
return is;
}
public:
operator std::string() const {
return data_;
}
};
int main(int, char *[]) {
non_blank line;
std::ifstream ifs("teste.txt");
while(ifs >> line) {
//std::cout << line; <----- error
std::string s = line;
std::cout << s << std::endl;
}
return 0;
}
I've got an error when trying to use a non_blank variable in a std::cout <<... expression. Shouldn't I be able to use a variable of the type non_blank anywhere I would use a std::string? Isn't it the purpose of the cast/conversion operator?? answer
Why can't I access the private variable string::data_ directly in the definition of the operator >>?
Here is the error I got:
..\main.cpp: In function `std::istream& operator>>(std::istream&, non_blank&)':
..\main.cpp:21: error: invalid use of non-static data member `non_blank::data_'
..\main.cpp:26: error: from this location
Shouldn't I be able to use a variable
of the type non_blank anywhere I would
use a std::string? Isn't it the
porpuse of the cast operator?
Not quite. If the compiler sees you doing something that it knows requires a std::string, it can call your conversion operator to get one. But in the case of the ostream operator <<, it doesn't have a single specific function to call, but rather quite a lot of them, all different and none matching precisely the actual type you mean to print. So it lists a whole bunch of candidates, none of which is a strong enough match. You need to define an ostream operator << for your type in order to make it print as it should.
As for your operator >>, you should make it not be a member of your class. Declare it as a friend within the class declaration if you must, but write the function itself outside.