Stream syntax for reading from std::vector (or other sequence)?
Imagine I have a Variant class which can represent a variety of POD types, plus std::string, and I have a template method T get_value(const Variant&)
that can extract the underlying types from it.
Assume I have a vector of these, ie. std::vector<Variant>开发者_Python百科 variants;
, and I want to read several values from it with a convenient syntax, like so:
int x;
double y;
std::string z;
// Get elements 0, 1, and 2 as int, double, and string respectively
streamlikeObject >> x >> y >> z;
The question is: what is a good way to form the hypothetical streamlikeObject
in the example? I can imagine creating my own class with an extraction operator but I am just interested as to whether there's something in the std library or maybe Boost which handles this sort of thing.
Or alternatively: how else can this data be extracted with a similar degree of code brevity? Maybe there is a better alternative to the stream syntax.
Something like (untested)
template <typename Iter>
class Extractor {
Iter cur;
Iter const &end;
public:
Extractor(Iter const &begin, Iter const &end)
: cur(begin), end(end) { }
template <typename T>
Extractor &operator>>(T &x)
{
if (cur == end)
throw SomeException();
x = cur->get_value();
++cur;
return *this;
}
};
Construct with Extractor<std::vector<Variant>::const_iterator> streamlikeObject(v.begin(), v.end());
.
Alternatively, if you only want to extract from containers, you may want to parametrize the template on the container type instead of the iterator type to save typing (pardon pun).
So let me make sure I understand this correctly.
You have a std::vector, and it contains arbitrary data. The contents of which are runtime-defined.
And you want to take this runtime-defined object and apply a compile-time sequence on it like this:
std::vector<Variant> >> val1 >> val2 >> val3;
I suppose your code will just throw if the current value doesn't match the expected type, yes?
You could use some of Boost.IOStream's facilities for this. You would basically be making a new stream type that uses your Variants instead of char
. And you would need a stream buffer that pulls from a (presumably const) reference to a container of these Variant
objects.
If the goal is to create something generic, I'd probably try something with std::tuple
, allowing usage like this:
std::tuple<int, double, std::string> input;
streamLikeObject >> input;
(Implementation left as an exercise for the reader.)
Something like this :
struct A
{
int a;
float b;
std::string c;
};
std::istream& operator>>( std::istream &is, const A &a )
{
is >> a.a;
is >> a.b;
is >> a.c;
return is;
}
精彩评论