oddRaven
oddRaven

Reputation: 672

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?

Upvotes: 14

Views: 16392

Answers (6)

Galik
Galik

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

WhiZTiM
WhiZTiM

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

1stCLord
1stCLord

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

Alessandro Power
Alessandro Power

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

James K. Lowden
James K. Lowden

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

Rakete1111
Rakete1111

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

Related Questions