Hello,
I am trying to read text from a simple text file.
The text file contains a list of emails and zipcodes, formated as follows:
email@site.com;zipcode where zipcode is 5 integers.

I am having an issue with the getline function, my error is "no instance of overloaded function".
Could someone please help me with this? I would like my error explained if possible, not just fixed.

        void createDatabase()
            {
                int zipcode;
                member inputStream;

                cout << "You have selected to create a database";
                cout << "\n\nPlease enter the zipcode of the database to create: ";
                cin >> zipcode;
                ifstream inputFile;
                inputFile.open("database.txt");

                while(!inputFile.eofbit)
                {
                    getline(inputFile, inputStream.email, ";");
                    cout << inputStream.email << endl;
                    getline(inputFile, inputStream.zip, \n);
                    cout << inputStream.zip << endl;
                }

            }

The third argument for getline() is the termination character, that is a variable of type char. Variables of type char can be indicated by using single quotes, ''. Double quotes indicate a variable of type string. The default termination char is the newline char, '\n', so you don't need to state it explicitly if you don't want to. I don't believe the escape char backslash followed by n will be interpretted as a char, but I could be wrong on that.

This isn't really an answer to your question, but if I were you, I'd just read in the whole line in one go and then have a separate piece of code to split the line into its individual fields. If you think about it, they are logically separate operations:

  1. Getting a record from file
  2. Parsing a string to construct a member object

In the future, for example, you might add more fields to each record and you don't want to have to change the file-reading code. So, if I were you, I'd restructure your code like this:

int createDatabase()
{
    std::vector< member > members;

    ifstream inputFile("database.txt");
    if ( ! inputFile.is_open() )
    {
        std::cerr << "Unable to open database file" << std::endl;
        return -1;
    }

    while( true )
    {
        std::string memberString;
        getline( inputFile, memberString );

        if ( inputFile.eof() )
            break;   // Stop reading at the end of the file

        members.push_back( member( memberString ) );
    }
}

You then need to add a way of constructing a member object from a std::string:

member::member( const std::string& objString )
{
    std::string::size_type iPos = objString.find( ";" );
    if ( iPos == std::string::npos )
        throw std::invalid_argument( "Bad member string" );

    this->email = objString.substr( 0, iPos );
    this->zip = objString.substr( iPos + 1 );
}

You might not want to do this in the constructor, you might want an empty constructor and an initialise() method on the member class or something, but the idea is the same.

As you cam see, this way if you decide to change the way the database is serialised, or add fields or whatever, you'll only have to change the workings of the constructor of the member class.

Thank you for the help :) I think that is a bit over my head though. I have only had one class in C++ and have done some minor learning outside of it. Also, member is a structure as follows:

struct member {
    string email;
    string zip;
}

It seems to me that the error "no instance of overloaded function" means you have not defined the proper namespace at the beginning of the program. This could cause the 3-parameter getline() to be unknown.

Also, see this about reading and looping (feof() is identical to your (.eofbit`)

It seems to me that the error "no instance of overloaded function" means you have not defined the proper namespace at the beginning of the program. This could cause the 3-parameter getline() to be unknown.

getline doesn't require a using namespace std; declaration. The issue is as identified by Lerner; on line 14 you need to do

getline(inputFile, inputStream.email, ';');

and

getline(inputFile, inputStream.zip, '\n');

on line 16 to get your code to build (note the single quotes).

On another note, the stuff with the constructors isn't too difficult. If you have a struct like:

struct member
{
    std::string email;
    std::string zip;
};

Then the compiler will be generating a couple of constructors for you. These are special functions that get called when you first declare an instance of a class, i.e. when you do

member m;

In this case, you're not passing any arguments to the constructor. This is the default constructor. The other constructor generated by the compiler is the copy constructor, which gets used when you copy the object, obviously! Be careful though, passing an object to a function by value calls the copy constructor as well (since a copy is created to be used inside the function). OK, that's great, but where it's useful is that you can also define your own constructors, which can build your object from whatever you want it to. You can also override the compiler-generated constructors too. Infact, if you define any constructor then the compiler will not make any of the ones it would normally make, so be careful of that. So, to make a constructor for your class, you just give it a member function with the name of the class (member in this case):

struct member
{
    member( const std::string& objString );   // Our new constructor

    std::string email;
    std::string zip;
};

To define what this new constructor does, you just do what I posted previously:

member::member( const std::string& objString )
{
    std::string::size_type iPos = objString.find( ";" );
    if ( iPos == std::string::npos )
        throw std::invalid_argument( "Bad member string" );
    this->email = objString.substr( 0, iPos );
    this->zip = objString.substr( iPos + 1 );
}

You can do this anywhere below the declaration of the struct in the same file, or in another file that #includes the declaration. So, now you can build a member object from a std::string, which you may have read from a file. Excellent. Remember though, you've defined your own constructor, so the compiler won't make the ones it normally does. So, now if you do member m; anywhere in your code, you will get a compiler error. This is no problem though, you can easily make another constructor that does nothing! (you can have an unlimited number of different constructors for your class/struct)

struct member
{
    member();   // A default constructor
    member( const std::string& objString );

    std::string email;
    std::string zip;
};

And the definition of the default constructor is the simplest of all:

member::member()
{
}

And there you go, member m; will now compile fine. The default constructor doesn't have to do nothing though. You might want to know that you member object hasn't had any values put into it yet, so you could make a default constructor that sets your member variables to some known state that means they're not set:

member::member()
{
    this->email = "not set";
    this->zip = "not set";
}

Then if you have some code that looks like this:

member m;
std::cout << "email = " << m.email << ", zip = " << m.zip << std::endl;

You will see the result email = not set, zip = not set. Cool.

The final thing to say about constructors is a feature called an initialiser list. This is allows you to pass values to the constructors of your member variables. In the default constructor above, you can see this->email = "not set", which is setting the value of email. Anything between in the curly braces is done after the member variables have been constructed. That means we're building a std::string with it's default constructor and then throwing that default-constructed string away and then assigning the value "not set" to it. We can avoid making this intermediate string by puting the "not set" in it as it's being constructed:

member::member() : email( "not set" ), zip( "not set" )
{
}

The : email( ... part is the initialiser list. In this case it's not really an issue, but sometimes the default constructor is expensive to call, or may not exist at all.

Anyway, that's more than enough of that. Have fun and Google stuff :o)

That's what happens when someone over-explains something when in fact a previous post answered the question...

If

The issue is as identified by Lerner

why the long disertation that only confused the poster?

Also:

the stuff with the constructors isn't too difficult.

It is when

I have only had one class in C++ and have done some minor learning outside of it.

When someone is struggling with one thing, heaping more on them is just more confusion. A step at a time.

Yeah, sorry about that! Didn't mean to over-load the OP. Once I got typing I didn't realise the post was getting so long. Should try and keep it relevant too, I guess :0)

Thanks for the help. I think I need to do more reading on file handling. I am having issues all over the place :(

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.