1

I'm trying to make a program that will open a txt file containing a list of names in this format (ignore the bullets):

  • 3 Mark
  • 4 Ralph
  • 1 Ed
  • 2 Kevin

and will create a file w/ organized names based on the number in front of them:

  • 1 Ed
  • 2 Kevin
  • 3 Mark
  • 4 Ralph

I'm having trouble outputting the vector into the new file "outfile.txt" On line 198 I get the error "no match for 'operator<<..."

What other methods can I use to output my vector?

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



using namespace std;

struct info
{
    int order;
    string name;
};

int sortinfo(info a, info b)
{
    return a.order < b.order;
}

int main()
{
    ifstream in;
    ofstream out;
    string line;
    string collection[5];
    vector <string> lines;
    vector <string> newLines;
    in.open("infile.txt");
    if (in.fail())
    {
        cout << "Input file opening failed. \n";
        exit(1);
    }
    out.open("outfile.txt");
    if (out.fail())
    {
        cout << "Output file opening failed. \n";
        exit(1);
    }

vector <info> inf;

while(!in.eof())
{
    info i;
    in >> i.order;
    getline(in, i.name);

    inf.push_back(i);
}

sort(inf.begin(), inf.end(), sortinfo);


ostream_iterator <info> output_iterator(out, "\n");
copy (inf.begin(), inf.end(), output_iterator);

in.close( );
out.close( );

return 0;
}
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Ron
  • 51
  • 1
  • 4
  • http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – Neil Kirk Nov 19 '14 at 20:49
  • Pass info by const reference to sortinfo to avoid copying it. You need to add stream-out operator << to info class. – Neil Kirk Nov 19 '14 at 20:50

2 Answers2

1

You need to overload the operator<< for info:

std::ostream& operator<< (std::ostream& stream, const info& inf) {
    return stream << inf.order << " " << inf.name;
}
Chris Drew
  • 14,926
  • 3
  • 34
  • 54
1

You could even overload the operator>> as well for the input side:

std::istream& operator>>(std::istream& is, info& i) {
    return std::getline(is >> i.order, i.name);
}
std::ostream& operator<<(std::ostream& os, info const& i) {
    return os << i.order << " " << i.name;
}

This lets you achieve more consistent code for input/output:

Live On Coliru

int main() {
    std::ifstream in ("infile.txt");
    std::ofstream out("outfile.txt");

    if (!in || !out) {
        std::cout << "file opening failed\n";
        return 1;
    }

    std::vector<info> inf;

    std::copy(std::istream_iterator<info>(in), {}, back_inserter(inf));
    std::sort(inf.begin(), inf.end());
    std::copy(inf.begin(), inf.end(), std::ostream_iterator<info>(out, "\n"));
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • This is very nice. Is there a good reason to make the I/O operators `friend`? – Chris Drew Nov 19 '14 at 21:50
  • Yes. If it's not a friend it's not a valid signature. Friend function declared in class are implicitly just namespace level free functions. It's a matter of taste whether you include them in the class, really. – sehe Nov 19 '14 at 21:53
  • Yeah, I understand it is a way of declaring non-member friend functions. I'm just of the [Meyer's school of preferring non-friend functions](http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197) – Chris Drew Nov 19 '14 at 22:01
  • Oh well, [updated for style](http://stackoverflow.com/posts/27027242/revisions) (do you spot the other style thing(s)?) – sehe Nov 19 '14 at 22:24
  • On your live demo I would make the `operator<` a non-member non-friend also :) – Chris Drew Nov 19 '14 at 22:31
  • You would, I didn't. But you can. There are subtle differences to consider, and I have no reason to prefer one or the other, given a complete lack of context. (Wellspotted, though) Cheers. – sehe Nov 19 '14 at 22:40