declaring input stream - c++

I have a C++ code with
ifstream myfile;
myfile.open("input");
and then has commands like:
myfile.getline(inp,256);
Question: How can I modify myfile.open("input") so that myfile is associated with cin instead of "input"?
I don't want to change all myfile.getline commands to cin.getline.
Declaring myfile=cin does not compile.

Use an istream& reference instead:
std::istream& myfile(std::cin);

Separate it out into a function and take the std::istream& as an argument. Then you can execute on both std::cin and myfile as you wish.

You can put your code into a function that takes a reference to a std::istream, e.g.
void process_data( std::istream & istr )
{ ... }
Then you can call this function both with any std::ifstream and with std::cin:
std::ifstream myfile;
...
process_data( myfile );
process_data( std::cin );

If you insist in using an std::ifstream you can replace the std::streambuf of the base std::istream (std::ifstream overloads rdbuf() so you can't use it directly):
std::ifstream file;
if (use_cin) {
file.std::istream::rdbuf(std::cin.rdbuf());
}

Related

How does istream::clear() behave if the stream is actually an ifstream?

I was wondering if calling clear() on an istream is the same / similar to calling close() on an ifstream.
My code looks like this:
void load_content(std::istream &ifs) {
std::string line;
getline(ifs, line);
...
ifs.clear();
}
Before, the argument was a std::ifstream and ifs.close() was called.
But to make it more testable, I changed it do istream such that I can pass filecontents as a stringstream.
Is this safe? In the normal usage of the program, there will always be an iftream passed to the function, only in tests it will be a stringstream.
Do I need to do more than this or is this fine?

How to assign istringstream and ifstream to an istream variable?

I want to have a variable of type istream which can hold either the contents of a file or a string. The idea is that if no file was specified, the variable of type istream would be assigned with a string.
std::ifstream file(this->_path)
and
std::istringstream iss(stringSomething);
to
std::istream is
I've tried just assigning them to the istream variable like I would with other objects that inherit from the same base class, but that didn't work.
How to assign istringstream and ifstream to an istream variable?
Base class pointers can point to derived class data. std::istringstream and std::ifstream both derived from std::istream, so we can do:
//Note that std::unique_ptr is better that raw pointers
std::unique_ptr<std::istream> stream;
//stream holds a file stream
stream = std::make_unique<std::ifstream>(std::ifstream{ this->_path });
//stream holds a string
stream = std::make_unique<std::istringstream>(std::istringstream{});
Now you just have to extract the content using
std::string s;
(*stream) >> s;
You can't assign to a std::istream but you can bind to a reference like this:
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
std::istringstream test_data(R"~(
some test data here
instead of in an external
file.
)~");
int main(int, char* argv[])
{
// if we have a parameter use it
std::string filename = argv[1] ? argv[1] : "";
std::ifstream ifs;
// try to open a file if we have a filename
if(!filename.empty())
ifs.open(filename);
// This will ONLY fail if we tried to open a file
// because the filename was not empty
if(!ifs)
{
std::cerr << "Error opening file: " << filename << '\n';
return EXIT_FAILURE;
}
// if we have an open file bind to it else bind to test_data
std::istream& is = ifs.is_open() ? static_cast<std::istream&>(ifs) : test_data;
// use is here
for(std::string word; is >> word;)
{
std::reverse(word.begin(), word.end());
std::cout << word << '\n';
}
}
Take a page out of the standard library: don't assign a value; assign a reference. That's probably what you want anyway.
std::istringstream iss(stringSomething);
std::istream& input(iss);
Because streams carry a lot of state, copying them is fraught with semantic questions. Consider for example what tellg should report in the copy after the original calls seekg. References by contrast answer the question transparently.
In C++, you cannot assign an object of type Child to a variable of type Parent, even if Child inherits from Parent. You can assign a pointer of type Child to a pointer of type Parent, however. You may want to consider dynamically allocating the objects.
In C++
std::istream is;
is an actual object, assigning to it will invoke the copy assignment operator which will copy the subobject of iss which is a std::istream into is and slice it. The example linked by LogicStuff will show that you need to assign a reference or pointer to iss like so:
std::istream &is_ref = iss;
The difference between values, references and pointers is fundamental to C++, I would advise getting a strong grasp of them.
std::istream can be constructed from a std::streambuf (basically the device that produces or consumes characters). All i/ostream objects have an associated std::streambuf and can be shared.
std::ifstream file(this->_path);
std::istringstream iss("str in gSo met hing");
std::istream A(iss.rdbuf()); // shares the same buffer device with iss
std::string str;
//////////////
while(A >> str) std::cout << str << " | "; //read everything from stream (~> iss)
std::cout << std::endl;
A = std::move(file);
while(A >> str) std::cout << str << " | "; //read from file, using same stream (~> file)

How to write out to a file and make it return the file

int fileReading(string signalFile){
ofstream fileName;
fileName.open(signalFile, ios::in | ios::binary);
//does more stuff here
fileName.close();
return 0;
}
How would I create a new file and switch the return type of the function to a file?
Do I need to create a class for this?
The easiest and probably the most consistent thing to do is to have your function take an fstream as argument (by reference) and then return it,
fstream& fileReading(fstream& strm)
{
// process it here
return strm;
}
This way you are not mixing file names with streams, so your function does only one thing: process a stream. Once you defined your function, you can use it like
fstream fileName("test.txt", ios::in | ios::binary); // we open the stream
fileReading(fileName); // and process the stream, will close automatically at exit from scope
If you try to return a local fstream (i.e. from inside a function), the compiler won't be able to (unless you use C++11), since fstream is non-copyable. In C++11 the compiler will use move semantics and move your local fstream into the returned stream. So in principle this should work:
fstream fileReading(const string& signalFile)
{
fstream fileName;
fileName.open(signalFile, ios::in | ios::binary);
//does more stuff here
// fileName.close(); // do not close it here
return fileName;
}
Then use as
fstream f = fileReading("test.txt");
However, the support for moveable streams seems to be broken in g++4.9 (works in g++5 and clang++). That's why the best is just to pass the stream by reference and return the reference.

istream function parameter vs inline std::cin

How these two function differs? Is there any different kinds of istream other than std::cin and what is the point of returning the istream?
using namespace std;
istream& readInput(istream& in, vector<string>& wordList)
{
string word;
while (in >> word)
{
wordList.push_back(word);
}
in.clear();
return in;
}
void readInput(vector<string>& wordList)
{
string word;
while (cin >> word)
{
wordList.push_back(word);
}
cin.clear();
}
cin is absolutely not the only one istream, I think that it is not even the most used one. Read about e.g. ifstream and istringstream.
Returning istream& from the function may be useful in various situations - it depends on the context. For just simple calls of readInput one can skip it and make the function void.

How to pass cin or ifstream object as argument function

I though this would work since ifstream inherits from istream
string getFileContents(istream& file_contents)
{
string result;
string line;
while (getline(file_contents, line))
result += line + "\n";
return result;
}
then I want to call this function like so:
ifstream file_input;
getFileContents(file_input);
...
getFileContents(cin);
but I get this error in visual studio:
'getFileContents' : cannot convert parameter 1 from std::istream to std::ifstream &
It should work; are you sure you didn't leave around a wrong prototype that has a parameter of type ifstream & instead of istream &?