Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use a vector range constructor?

I want to load all the lines from a text file into a vector<string by using its range constructor and then output them through cout:

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

using namespace std;

int main()
{
  ifstream file("file.txt");
  vector<string> strings(istream_iterator<string>(file) , istream_iterator<string>());

  for(auto s : strings)
    cout << s << endl;

  return 0;
}

When trying to compile the above code I get several errors, for instance:

error: no matching function for call to ‘begin(std::vector<std::basic_string<char> > (&)    (std::istream_iterator<std::basic_string<char> >, std::istream_iterator<std::basic_string<char> > (*)    ()))’
   for(auto s : strings)
                ^

and several others...

I think I'm missing something obvious here, can anyone please help?

like image 419
JLagana Avatar asked Jun 07 '14 20:06

JLagana


1 Answers

You have fallen victim to the Most Vexing Parse, where the compiler sees your declaration as a function strings returning a vector<string>, taking two arguments:

  • an istream_iterator<string> called file
  • an unnamed pointer to function taking no arguments and returning a istream_iterator<string>.

To eliminate the vexing parse, use an extra pair of parentheses around the first argument:

vector<string> strings((istream_iterator<string>(file)) , istream_iterator<string>());
//                     ^                              ^

or, alternatively in C++11, use curly braces for the strings constructor

vector<string> strings{istream_iterator<string>(file) , istream_iterator<string>()};
//                    ^                                                           ^

NOTE: Clang warns you about it through -Wvexing-parse (on by default).

like image 57
TemplateRex Avatar answered Oct 09 '22 03:10

TemplateRex