2

I am trying to store binary data that should have the type of a std::complex< float > into a vector, through iterating over each element of the stream buffer. However I keep getting an error saying

no matching function for call to ‘std::istreambuf_iterator<std::complex<float> >::istreambuf_iterator(std::ifstream&)’
 std::for_each(std::istreambuf_iterator<std::complex<float> >(i_f1),

I've tried searching for a solution but cannot find anything that would work. I am also trying to follow an example given in How to read entire stream into a std::vector? . Furthermore I'm compiling using g++ and -std=c++11.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>
#include <boost/tuple/tuple.hpp>
#include <algorithm>
#include <iterator>

int main(){

    //path to files
    std::string data_path= "/$HOME/some_path/";

    //file to be opened
    std::string f_name1 = "ch1_d2.dat";


    std::ifstream i_f1(data_path + f_name1, std::ios::binary);
    if (!i_f1){
        std::cout << "Error occurred reading file "<<f_name1 <<std::endl;        std::cout << "Exiting" << std::endl;
        return 0;
     } 

    //Place buffer contents into vector 
    std::vector<std::complex<float> > data1;

    std::for_each(std::istreambuf_iterator<std::complex<float> >(i_f1), 
        std::istreambuf_iterator<std::complex<float> >(), 
        [&data1](std::complex<float> vd){
        data1.push_back(vd);
        });

   // Test to see if vector was read in correctly
   for (auto i = data1.begin(); i != data1.end(); i++){
        std::cout << *i << " ";

    }

    i_f1.close();
    return 0;
}

I am quite lost at what I'm doing wrong, and am thus wondering why the

std::istreambuf_iterator() 

does not accept the stream I am giving it as parameter? Also the error message is confusing me as it seems to imply that I am calling the function in a wrong way, or a function that is non-existent.

Thanks

Julian
  • 23
  • 9

2 Answers2

4

You want to read std::complex from i_f1 (which is a std::ifstream) using operator>> for std::complex, so you need a std::istream_iterator instead of std::istreambuf_iterator1:

std::for_each(std::istream_iterator<std::complex<float> >(i_f1), 
    std::istream_iterator<std::complex<float> >(), 
    [&data1](std::complex<float> vd){
        data1.push_back(vd);
    });

Your code can actually be simplified to:

std::vector<std::complex<float>> data1{
    std::istream_iterator<std::complex<float>>(i_f1), 
    std::istream_iterator<std::complex<float>>()};

1 std::istreambuf_iterator is used to iterate character per character on, e.g., a std::basic_istream, not to iterate over it using overloads of operator>>.

Holt
  • 36,600
  • 7
  • 92
  • 139
  • Actually, istreambuf_iterator can quite deliberately be instantiated from an std::istream& ... but it has to have the same character type. – Lightness Races in Orbit Jun 03 '19 at 12:22
  • @LightnessRacesinOrbit Thanks, I've actually never used `streambuf_iterator` so I did not know its really use. I've updated the answer. – Holt Jun 03 '19 at 12:25
4

You're probably using the wrong tool for the job.

You're trying to use a buffer iterator, which iterates over the constituent parts of a stream's buffer. But you're telling your computer that the buffer is one of complex<float>s … it isn't. An ifstream's buffer is of chars. Hence the constructor you're trying to use (one that takes an ifstream with a buffer of complex<float>) does not exist.

You can use an istream_iterator to perform a formatted iteration, i.e. to use the stream's magical powers (in this case, lexically interpreting input as complex<float>s) rather than directly accessing its underlying bytes.

You can read more on the previous question "the difference betwen istreambuf_iterator and istream_iterator".

The example you linked to does also go some way to explaining this.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055