Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
580 views
in Technique[技术] by (71.8m points)

c++ - How to convert from std::vector<float> to std::istream?

I have an std::vector and the function expects an std::istream:

callMe(std::istream& is)

What is the best way to do the conversion? Is there something more clever than?

std::stringstream sstr;
for(int i = 0; i < myVector.size(); ++i) {
    sstr << myVector[i] << " ";
}
std::istringstream istr{sstr.str()};
callMe(istr);

EDIT: Thanks for the suggestions so far! Updated code:

std::stringstream sstr;
for(const float& val : myVector) {
    sstr << val << " ";
}
callMe(sstr);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...