Roman Rdgz
Roman Rdgz

Reputation: 13254

Cannot get vector size when constructed from istreambuf_iterator

I'm trying to read a binary file full of std::complex<float>. I tried the following code, as suggested in this SO answer:

#include <complex>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>


void readRawFile(const std::string inputFile){
    std::ifstream input(inputFile, std::ios::binary);
    std::vector<std::complex<float>> auxBuffer(std::istreambuf_iterator<std::complex<float>>(input), std::istreambuf_iterator<std::complex<float>>());
    std::cout << "Number of raw samples read: " << auxBuffer.size();
}

int main(){
    readRawFile("myRawFile.raw");
    return 0;
}

And I get the following compilation error:

In function 'void readRawFile(std::string)': 12:59: error: request for member 'size' in 'auxBuffer', which is of non-class type 'std::vector<std::complex<float> >(std::istreambuf_iterator<std::complex<float> >, std::istreambuf_iterator<std::complex<float> > (*)())'

I don't understand why can't I access the size method of a vector I just created without compilation errors. I suppose it has something to do with how the vector is being created, but it seems strange to me that it doesn't give an error there instead.

Any explanation for this?

Upvotes: 1

Views: 302

Answers (2)

WhiZTiM
WhiZTiM

Reputation: 21576

You've hit C++'s Most Vexing Parse. You declaration was interpreted as a function declaration:

You can either:

void readRawFile(const std::string inputFile){
    std::ifstream input(inputFile, std::ios::binary);

    auto start = std::istream_iterator<std::complex<float>>(input);
    auto stop = std::istream_iterator<std::complex<float>>();

    std::vector<std::complex<float>> auxBuffer(start, stop);
    std::cout << "Number of raw samples read: " << auxBuffer.size();
}

Or use Uniform Brace Initialization (C++11):

void readRawFile(const std::string inputFile){
    std::ifstream input(inputFile, std::ios::binary);
    std::vector<std::complex<float>> auxBuffer{std::istream_iterator<std::complex<float>>(input), std::istream_iterator<std::complex<float>>()};
    std::cout << "Number of raw samples read: " << auxBuffer.size();
}

Live Here

Upvotes: 3

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

The answer you copied shows how to read raw characters from a stream into a buffer. That's a correct use of istreambuf_iterator.

You are trying to extract complex numbers from a stream. That's a completely different operation, which involves reading the characters and then parsing them with operator<<. That's not what istreambuf_iterator is for. The type istreambuf_iterator<complex<float>> would try to extract characters of type complex<float> from a basic_streambuf<complex<float>> which is nonsense. That's not a character type, and you can't have a streambuf containing complex numbers as its raw characters.

istreambuf_iterator is for reading single characters from a streambuf, not for parsing characters and interpreting them as (complex) numbers or other types.

You need to use std::istream_iterator<X> to extract X values from an istream, so after you fix the most vexing parse, you need to use std::istream_iterator<std::complex<float>> as the iterator type.

Upvotes: 4

Related Questions