So we have all been there. I have a nice object, I have a constructor for it, the object can resolve true if it is created correctly, but it also has other state, so I can happily write:
if (const auto& str = std::ofstream("/tmp/myfile"))
{
str << "Oh that was easy\n";
}
But what I would really like to do is try a few alternates:
if (const std::stream& str = (std::ofstream("/tmp/myfile") || std::ofstream("/temp/myfile") || std::ofstream("./myfile")) )
{
str << "Oh that was not so easy\n";
}
Clearly not! I potentially opened 3 files, but cast them to "true" bool, and couldn't cast back to std::stream, of course. If I overload operator || for stream rvals then it opens all 3 files because the lazy evaluation is forgotten!
I know, std::stream is perhaps a poor example, but 20 pages later I will have finished explaining my option string processor, so lets stick with std::stream.
What I would expect might be possible would be something like:
if (const std::stream str = (std::piecewise_construct(std::ofstream,"/tmp/myfile") || std::piecewise_construct(std::ofstream,"/temp/myfile") || std::piecewise_construct(std::ofstream,"./myfile")) )
{
str << "Oh that maybe makes sense?\n";
}
To do this it looks like I might need 2 overloads of operator ||, one that takes two unsolved piecewise_construct and resolves the left one to get started, and another that takes an rval object on the left and only evaluates the right hand side if it is "failed". Something like:
template<class PC2>
std::stream operator ||(std::stream&& str, const PC2& pc2)
{
if (str)
return std::move(str);
return pc2.construct();
}
template<class PC1, class PC2>
std::stream operator ||(const PC1& pc1, const PC2& pc2)
{
return operator||(pc1.construct(), pc2);
}
Where PCx here is the piecewise construct.
But I can see straight away that std::peicewise_construct is just a tag. It doesn't itself have any functionality. Also I am fighting to find any way I can make this work with template FINAE restrictions: Not much point creating two unrelated types that can't be moved. There are a number of similar "tricks" floating around in C++, such as std::function or lambdas that look to do a similar job?
Right now I would love a solution in C++11 that doesn't look like Frankenstein after a fight with his monster, but don't feel restricted if the feature I want is just a version away!
Meanwhile I have 3 copies of basically the same argument value parser and storage because customers can't agree what the option should be called between versions.
I guess I'm after some sort of customisable template, rather than something hardwired to the specific class, in this case std::stream, and even stream has numerous constructors. A common enough pattern with handles is code that basically want to do h = (open(O_APP) || open(O_CREATE) || open(O_TRUNC)) {except that is C, not objects}.
One way forward is some sort of templated class that holds the std::bind and knows how to construct, in turn built from a helper function. And perhaps the type of that object will allow the type protection that I also desire.
And another note... In the example, I am using std::istream with just 1 argument, but of course the constructor for istream can take a number of arguments and has a number of alternate constructors, and my internal usecase has at least 3 and probably more options in future, so it really needs to support that arbitrary argument list template stuff we all love.