Example below illustrates my question best:
class Stream
{
public:
Stream(std::ostream& os)
:
stream(os)
{
}
auto getStream()
{
return std::pair<std::ostream&, std::unique_ptr<StreamDelegate>>(stream, std::make_unique<StreamDelegate>(stream));
}
private:
std::ostream& stream;
};
int main()
{
Stream os(std::cout);
os.getStream() << "input1" << "input2";
//execute some code without explicitly calling it
//such os.getStream() << std::endl;
}
My (working) attempt achieving this functionality:
class StreamDelegate
{
public:
StreamDelegate(std::ostream& os)
:
stream(os)
{
}
~StreamDelegate()
{
//some delegated functionality
//exmpl:
stream << std::endl;
}
private:
std::ostream& stream;
};
class Stream
{
public:
Stream(std::ostream& os)
:
stream(os)
{
}
auto getStream()
{
return std::pair<std::ostream&, std::unique_ptr<StreamDelegate>>(stream, std::make_unique<StreamDelegate>(stream));
}
private:
std::ostream& stream;
};
int main()
{
Stream os(std::cout);
os.getStream().first << "input1" << " input2";
os.getStream().first << "line2: input1" << " line2: input 2";
std::cin.get();
}
Are there other, prefereably more elegant, ways to achieve this functionality?
Also, i see a possible pitfall in my code. Ilustrated in the code below:
int main()
{
Stream os(std::cout);
auto pitfall = os.getStream();
pitfall.first << "line1";
pitfall.first << "should be line 2";
std::cin.get();
}
Since the return value of os.getStream()
is assigned to a variable, there is no destruction of the StreamDelegate
and thus no desired behaviour.
I dont intend for Stream::getStream()
to be assigned to a variable, but it if there is a way around this i'd like to know.
Also I am aware that I could have avoided having StreamDelegate
by implementing the Stream
destructor in the same manner as StreanDelegate
, but i possibly want this to work on a singleton.
I think your idea to use RAII is good. If you implement templated operator<<
for your Stream
and have that return your StreamDelegate
it get easier to use, and it's harder to mess up the destruction by assigning to a variable.
#include <iostream>
class StreamDelegate
{
public:
StreamDelegate(std::ostream& os) : stream(os) {}
~StreamDelegate() {
//some delegated functionality
//exmpl:
stream << std::endl;
}
template <typename T>
StreamDelegate& operator<<(T&& val) {
stream << std::forward<T>(val);
return *this;
}
StreamDelegate& operator=(const StreamDelegate&) = delete;
StreamDelegate(const StreamDelegate&) = delete;
private:
std::ostream& stream;
};
class Stream
{
public:
Stream(std::ostream& os) : stream(os) {}
template <typename T>
StreamDelegate operator<<(T&& val) {
stream << std::forward<T>(val);
return StreamDelegate(stream);
}
private:
std::ostream& stream;
};
int main()
{
Stream os(std::cout);
os << "input1" << " input2";
os << "line2: input1" << " line2: input 2";
std::cin.get();
}
Edit
I explicitly declared both copy-constructor and copy-assignment for StreamDelegate
as delete, so it's no longer possible to do
auto delegate = os << "input3";