1

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?

Community
  • 1
  • 1
Roman Rdgz
  • 11,378
  • 36
  • 110
  • 192

2 Answers2

4

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.

Jonathan Wakely
  • 153,269
  • 21
  • 303
  • 482
3

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

WhiZTiM
  • 19,970
  • 3
  • 36
  • 56
  • @WiinZTim. the `T object { }` as constructor, is called **direct initialization** or **uniform Brace Initialization**? – Shakiba Moshiri Feb 09 '17 at 12:23
  • The brace inicialization does not seem to work: no matching function for call to ‘std::vector >::vector()’ – Roman Rdgz Feb 09 '17 at 13:30
  • In fact both suggested implementations give compilation errors. I believe the first one is due to the lack of support for complex at the istreambuf_iterator constructor – Roman Rdgz Feb 09 '17 at 13:36
  • 2
    It will work if you use `istream_iterator` not `istreambuf_iterator`, which is necessary because you're trying to parse values from the stream not extract single characters. – Jonathan Wakely Feb 09 '17 at 13:46
  • @k-five, I believe its actually [*direct-initializtion*](http://en.cppreference.com/w/cpp/language/direct_initialization). The other term is a broader term (outside the standard) which covers `T object{}`, and additionally things like `T myFunc(){ ...; return {}; }` – WhiZTiM Feb 09 '17 at 14:18
  • @JonathanWakely, It was a stupid oversight on my part. I thought I saw `std::istream_iterator`. I've corrected my answer.. However, For the OP's case, I seem to be unable to suppress the Most Vexing Parse using additional parenthesis as seen [here](http://coliru.stacked-crooked.com/a/a782c8b9b9d56940). The compiler(GCC, Clang, MSVC) seems to be applying the `comma` operator rather. I am probably missing something there?? – WhiZTiM Feb 09 '17 at 14:30
  • @WhiZTiM you need extra parentheses around the individual parameters, not around all the parameters. i.e. `T t((arg), (arg));` not `T t(((arg), (arg)));`. Otherwise you're trying to call the function with a single (invalid) argument. – Jonathan Wakely Feb 09 '17 at 15:16