Sending a string variable as a parameter to open a file - c++

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().

Related

How to store both an int or a string in a single variable, without losing their type?

#include<iostream>
using namespace std;
class Name
{
public:
void tell(string s){cout<<"Your name is "<<s<<endl;}
void tell(int i){cout<<"Your age is "<<i<<endl;}
};
int main()
{ Name m; string s;
while(s!="n")
{
cout<<"Input your name or age"<<endl;
cin>> s;
m.tell(s);
}
return 0;
}
The variable 's' should be able to store an int as well as string argument, without losing its type;
so that, the 'int' overload gets invoked when I pass an int argument
and the 'string' overload gets invoked when I pass a string argument to tell()
"Input your name or age" - well, you at least need to know, what you are about to store, i.e. how to interpret the input value.
If your intent is to detect if the input is a number, you could try to convert to integer, and if that conversion succeeds store the value as int, otherwise as string.
For example with boost::lexical_cast:
#include <boost/lexical_cast.hpp>
cin >> s;
try {
int age = boost::lexical_cast<int>(s);
m.tell(age);
} catch (const bad_lexical_cast &) {
m.tell(s);
}
If you don't have boost, you can try to use different means of conversion, like atoi() (difficult to detect error) or strtol() (possible to detect error) - see also How do I check if a C++ string is an int?.

Meaning of class(*)() in gcc

I'm having trouble understanding this compiler error. I wrote class(*)() in the post title because the class I am instantiating is called "opaque", but that name is not informative or relevant. It is a templatized Circular Buffer and some tests. I am using the opaque class to test the data structure with full class/struct types. I am also testing with primitives (int at the moment) and that test function does not give me this compiler error. There is more code than this, but I've provided what I think are the relevant sections.
The full code is here if you are interested.
gcc error:
tests.cpp: In function ‘bool opaque_fill_test(int)’:
tests.cpp:97:23: error: no matching function for call to ‘CircBuf<opaque>::remove(opaque (*)())’
tests.cpp:
struct opaque {
int id;
opaque(int n): id(n) {}
opaque operator=(const opaque &o) { this->id = o.id; }
};
opaque rcv();
CircBuf<opaque> c(size);
for (int i=0; i<size; i++) {
if ( c.remove(&rcv)) {
if (rcv.id != i ) {
cout << "wrong value: " << rcv << " "
<< "should be: " << i << endl;
return false;
}
} else {
cout << "remove fail at i=" << rcv << endl;
return false;
}
}
CircBuf.h:
template<typename T> class CircBuf {
...
template<typename T> bool CircBuf<T>::remove(T *t) {
...
*t = data[front];
...
if i declare an opaque* and pass that to remove instead:
opaque rcv();
opaque* p = &rcv;
for (int i=0; i<size; i++) {
if ( c.remove(p)) {
...
...
i get a similar error:
tests.cpp: In function ‘bool opaque_fill_test(int)’:
tests.cpp:96:16: error: cannot convert ‘opaque (*)()’ to ‘opaque*’ in initialization
If you have the declaration foo x();, the expression &x will actually be a function pointer assignable to something like foo *(y)(). The p variable in your last example isn't such a function pointer, but simply a pointer to an opaque struct. Thus you cannot assign the function pointer to that variable.
[edit]
Just remembered: maybe you meant to declare an opaque variable and initialize it using the default constructor. Leave out the parentheses then. It's a left-over syntax from C. You can only use the parentheses there if you actually put values in between to call a different constructor.
What you are doing with:
opaque rcv();
is that you are "declaring a function" with the name rcv having the return type opaque, and taking no arguments. Check this link
Drop the paranthesis:
opaque rcv;
You hit the most vexing parse.
if i declare an opaque* and pass that to remove instead:
opaque rcv();
That declares a function returning opaque, not a default-initialized opaque. Instead use opaque rcv; or opaque rcv = {};.
As for the error message, opaque (*)() is the type of a pointer to a function returning opaque. The name of the "function" was implicitly converted to a pointer when used for something besides a call.

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

can i pass std::ostream& to a function expecting std::ofstream

What i'm trying to do is:
I want to redirect my error message erither to std::cerr or to a file
depending upon the command-line argument. If there is no log file provided then the program should output the error message on screen.
Here is my approach:
class A {
void SetLogFileStream(T& err_outstream);
};
//main.cpp
A a;
std::string filename;
T1* t1;
if(argc>2) {
filename = argv[1]; //if provided by command line
std::ofstream fp(filename);
t1 = &fp;
}
else {
std::ostream* err_outstream = &std::cerr;
t1 = err_outstream;
}
a.SetLogFileStream(t1);
what should be the argument type of the function SetLogFileStream
or the type T1
so that i can pass a pointer either to file or to std::cerr
No. But the reverse is true. You can pass an std::ofstream to a function expecting an std::ostream&, or an std::ofstream* to a function expecting an std::ostream*. So your function should accept either an std::ostream ref or pointer.
Declare the method as this:
class A {
void SetLogStream(std::ostream& err_outstream);
};
There are several problems with your code. The file stream opened gets out of scope and is destroyed. You need to fix it like this:
std::ofstream f; // <-- this have to remain in scope while you use it for 'a'
A a;
if(args > 2) {
f.open(argv[1]);
a.SetLogStream(f);
} else {
a.SetLogStream(cerr);
}
The type should be std::ostream. It woun't work exactly as you've coded it because your function parameter is a reference and your argument is a pointer. But fix that (either way) and it will work.

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