The issue is that std::istream
is inherently character-based. If you want to keep using callMe(std::istream& is)
as an interface, you are bound to convert every element of myVector
to characters and back at some point. If you want to stick with this option, I personally find ostream_iterator
an elegant solution:
copy(begin(data), end(data), std::ostream_iterator<float>(sstr));
Full example:
void callMeStream(std::istream &is)
{
float f1;
is >> f1;
std::cout << "Stream: " << f1 << std::endl;
}
// ...
std::vector<float> data = {3.5, 1.5, 2.5 /* ... */};
std::stringstream sstr;
copy(begin(data), end(data), std::ostream_iterator<float>(sstr));
callMeStream(sstr); // Output: "Stream: 3.51"
If you are willing to change the signature of callMe
, this conversion can be avoided:
template <class T>
void callMeTemplate(T &is)
{
float f1;
is >> f1;
std::cout << "Template: " << f1 << std::endl;
}
#define NO_ELEMENT -1.0;
class data_wrapper
{
std::vector<float>::const_iterator current;
const std::vector<float>::const_iterator last;
public:
data_wrapper(const std::vector<float> &data) : current(begin(data)), last(end(data)) {}
data_wrapper &operator>>(float &value)
{
if (last == current)
{
value = NO_ELEMENT;
}
else
{
value = *current++;
}
return *this;
}
};
// ...
data_wrapper wrapper(data);
callMeTemplate(wrapper); // Output: "Template: 3.5"
In the second example, the float
value never gets converted to a character sequence, and could accept both data_wrapper
and std::istream
types. Of course, if you are willing to change the signature of callMe
entirely, you might as well change it to accept a begin/end iterator range or a vector
directly.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…