I am trying to create a constructor to load a resource from any istream given to it. I cannot seem to figure out the best way to pass the istream parameter into a constructor.
Loader::Loader(istream stream);
This one is obviosly bad due to object slicing, so no option.
Loader::Loader(istream& stream);
This is what I am using now and seems fairly alright. It has one significant issue though - you can't give it a temporary since temporaries cannot bind to non-const references! For example, the following won't work:
Container():
mLoader(ifstream("path/file.txt", ios::binary)
{
}
This is rather a limitation since I am now forced to store the ifstream as a member variable of Container just to extend its lifetime.
Since the problem is with non-const references, one could have though of this:
Loader::Loader(const istream& stream);
But since .seek() etc are non-const, this is not an option either...
So, how can this problem be solved in a neat way?
if your compiler is c++11 or better you can simply provide a version of the constructor that takes the istream
as an r-value reference:
void Loader::Loader(std::istream&& is)
quick example:
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
struct Loader
{
Loader(std::istream& is)
{
read(is);
}
Loader(std::istream&& is)
{
read(is);
}
void read(std::istream& is)
{
is >> std::quoted(x);
is >> std::quoted(y);
}
std::string x, y;
};
std::ostream& operator<<(std::ostream& os, const Loader& l)
{
os << "x = " << l.x;
os << ", y = " << l.y;
return os;
}
auto main() -> int
{
using namespace std;
Loader l(istringstream(R"text("donkey" "horse")text"));
cout << l << endl;
istringstream not_temp(R"text("apple" "banana")text");
Loader l2(not_temp);
cout << l2 << endl;
return 0;
}
expected output:
x = donkey, y = horse
x = apple, y = banana
The example
Container():
mLoader(ifstream("path/file.txt", ios::binary)
{
}
… is ill-conceived, because the lifetime of the temporary would be just the constructor call. Then you'd be left with a dangling reference. Using that reference would be Undefined Behavior.
However, technically, in order to be able to pass a temporary to a reference-to-non-const
formal argument, just define a little helper like this:
template< class Type >
auto temp_ref( Type&& o )
-> Type&
{ return o; }
Then you can call e.g. foo( temp_ref( Whatever() ) )
, but just keep in mind that the lifetime of that temporary is the full-expression that it occurs in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With