Reputation: 672
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?
Upvotes: 14
Views: 16392
Reputation: 48635
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';
}
}
Upvotes: 10
Reputation: 21576
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)
Upvotes: 1
Reputation: 880
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.
Upvotes: 1
Reputation: 2472
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.
Upvotes: 1
Reputation: 7837
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.
Upvotes: 1
Reputation: 48998
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;
Upvotes: 11