C++ callback function issue - c++

I have written a simple C++ program to accept a callback.
What callback does? the callback is the second argument of the main function and it simply returns a string, that string is then inserted into a .txt file by main function.
What is the error? Visual studio 2013 throws this error:
error C2664: 'void WriteToFile(std::string,std::string (__cdecl *)(std::string))' : cannot convert argument 2 from 'std::string' to 'std::string (__cdecl *)(std::string)'
Here is the code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void WriteToFile(string filename, string (*f)(string) )
{
ofstream FileProcessor;
FileProcessor.open(filename, ios::app);
FileProcessor << &f << endl;
}
string Printer(string Content)
{
return Content;
}
int main()
{
WriteToFile("test.txt", Printer("exampleText"));
}

AFAIK Printer("exampleText") is passed incorrectly. The second argument of function WriteToFile accepts a pointer to function. So just pass the function Printer.
The argument for the passed function pointer should be sent as different argument.
Something like-
void WriteToFile(string filename, string (*f)(string), string mystring )
{
ofstream FileProcessor;
FileProcessor.open(filename, ios::app);
FileProcessor << f(mystring) << endl;
}
and then called like
WriteToFile("test.txt", Printer, "exampleText");

WriteToFile is expecting the second argument to be a function pointer, not the result of a function call. Change the call to look like this:
WriteToFile("test.txt", Printer);
Still, it doesn't make much sense, because &f is the address of the function, so it'll just print some hex value. You probably want to call the function pointer:
FileProcessor << (*f)("exampleText") << endl;
For passing the argument, you have two options. Vinayak Garg listed one, which is to add a third argument to WriteToFile. The other one is to use std::bind.
WriteToFile("test.txt", std::bind(&Printer, "exampleText"));
In the latter case it will not look like it takes an argument however. Your definition of WriteToFile should look like this (untested):
void WriteToFile(string filename, const std::function<string()> &f )
{
...
FileProcessor << f() << endl;
}

Related

Passing Multiple Strings in Concatenation Attempt to an ostringstream Parameter

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

Passing strings by reference and value in C++

I want to declare a string, initialize it by passing it by reference, and then pass it by value to the 'outputfile' function.
The code below works, but I don't know why. In main I would expect to pass the string 'filename' like
startup(&filename)
But that gives an error, and the code below doesn't. Why? Also, is there a better way to do this without using a return value?
#include <iostream>
#include <string>
using namespace std;
void startup(std::string&);
void outputfile(std::string);
int main()
{
std::string filename;
startup(filename);
outputfile(filename);
}
void startup(std::string& name)
{
cin >> name;
}
void outputfile(std::string name)
{
cout << name;
}
Your code works as expected.
&filename returns the memory address of (aka a pointer to) filename, but startup(std::string& name) wants a reference, not a pointer.
References in C++ are simply passed with the normal "pass-by-value" syntax:
startup(filename) takes filename by reference.
If you modified the startup function to take a pointer to an std::string instead:
void startup(std::string* name)
then you would pass it using the address-of operator:
startup(&filename)
As a side note, you should also make the outputfile function take its parameter by reference, because there's no need to copy the string. And since you're not modifying the parameter, you should take it as a const reference:
void outputfile(const std::string& name)
For more info, here are the rules of thumb for C++ regarding how to pass function parameters.

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&)'

Strange behavior of stringstream passed by reference

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".

operator<< and std::stringstream reference?

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;
}