Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

STL and structs/classes

Status
Not open for further replies.

DarkAlchemist

Programmer
Jan 19, 2004
18
US
This is what I came up with but it refuses to compile can anyone tell me what is wrong?

class Country
{
public:
std::string CountryName;
std::string PersonsName;
std::string Coords;
};

std::vector <Country> places;
Country d;

int main(int argc, char* argv[])
{
d.CountryName = &quot;USA&quot;;
d.Name = &quot;Joe Smyth&quot;;
d.Coords = &quot;10.0N 20.4W&quot;;
places.push_back(d);
std::vector<string>::iterator begin = d.Coords.begin();
std::vector<string>::iterator end = d.Coords.end();
std::vector<string>::iterator my_iterator = std::find(begin, end, &quot;10.0N 20.4W&quot;);
return 0;
}

The iterator sections are the ones with the problems. What I want to do is find a match on the coords then I can grab the rest of the record. The way I had been doing it was to have 3 vectors. Btw, I do wish to use a vector not a list or a map.

Thank you.
 
Your vector holds Country objects, not strings, so you will have to find the Country object that matches your criterion. Your criterion is that the Coords match.

One way to do this is to make a binary predicate that takes a
Code:
const Country&
and
Code:
const std::string&
and returns a bool that is true if the Coords member matches the string. Your iterator should be
Code:
std::vector<Country>::iterator my_iterator
, and then you can use find_if with your predicate to find the matching Country. Note that instead of creating iterators for begin and end, just use
Code:
d.begin()
and
Code:
d.end()
inside the find_if call.

Another solution might be better if you fill your vector first with all the data, and then do searches on it later to find Countries with specific Coords. You can write a less than function for Country that simply compares the Coords string. Then sort the vector after all the data has been entered using std::sort. Once that is done, the lookups will be much faster, and you can use equal_range() or lower_bound() without having to write a separate predicate.
 
UGH :( I suppose I better stick with parallel vectors for now and just use 3 vectors and use find on the coords vector and then take the iterator-begin to find my other related fields. Much less work doing it that way regardless how it looks but no not happy I have to do it this way just its the only way I am comfortable with it seems.

Thank you.
 
Just wanted to add this

class Country
{
public:
std::string CountryName;
std::string PersonsName;
std::string Coords;
};

std::vector <Country> places;
Country d;

int main(int argc, char* argv[])
{
d.CountryName = &quot;USA&quot;;
d.PersonsName = &quot;Joe Smyth&quot;;
d.Coords = &quot;10.0N 20.4W&quot;;
places.push_back(d);
// std::vector<string>::iterator begin = d.Coords.begin();
// std::vector<string>::iterator end = d.Coords.end();
std::vector<Country>::iterator my_iterator = std::find(d.begin(), d.end(), &quot;10.0N 20.4W&quot;);
return 0;
}
now I am swatting the bugs as I see them then I will attempt predicates and find_if but here is the bugs

error C2039: 'begin' : is not a member of 'Country'
error C2039: 'end' : is not a member of 'Country'

What am I missing now?
 
I assume you mean something like this:

Code:
class Country
{
        public:
        std::string     CountryName;
        std::string     PersonsName;
        std::string     Coords;

		// Note: this is perhaps not so clever if you want
		// to be able to do a find by CountryName instead
		bool operator == (const std::string& coords)
		{
			return Coords == coords;
		}
};

// Typedef for clarity
typedef std::vector <Country> CountryVector;
CountryVector places;

Country d;

int main(int argc, char* argv[])
{
        d.CountryName = &quot;USA&quot;;
        d.PersonsName = &quot;Joe Smyth&quot;;
        d.Coords = &quot;10.0N 20.4W&quot;;
        places.push_back(d);
        CountryVector::iterator my_iterator = std::find(places.begin(), places.end(), std::string(&quot;10.0N 20.4W&quot;));
		cout << (*my_iterator).CountryName; // &quot;USA&quot;
        return 0;
}



/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
I haven't tested the code yet but I would like to know what this part is for?

bool operator == (const std::string& coords)
{
return Coords == coords;
}
 
PerFnurt's example is a good one. I accidentally said
Code:
d.begin()
instead of
Code:
places.begin()
, which is why you got the compile error.

And don't forget to look at the option of sorting the vector after you fill it. It is the more efficient way to go, and is not much harder to implement. You just need an operator< that is similar to PerFnurt's operator== but takes a const Country& argument instead.
 
The operator== is used to &quot;find&quot; the Country you want in the list. His version takes a string becuase you are trying to pass in a string to find. It compares that string only to the Coords field of the Country, because in your simple example you are only trying to look up based on Coords. You must define your own operator== to get the specialized behavior of comparing a Country to a string when you use find().

If you ever need to look up based on CountryName, then a more complicated example will be necessary. Also, I think operator== is generally better to implement as a non-member function. Of course, if you were to do that, then you might as well just use it as a predicate in find_if.
 
Well, what would happen if I wanted to find on any of those fields besides coord? What I mean is maybe I wish to search based on coords this time but maybe next time based on Country then the next time maybe base the search on PersonsName?
 
Forget the == operator mentioned above. its a rather ugly solution anyway.
You can use the find_if function uolj mentioned, perhaps combined with function objects (ie classes that behaves like a function, aka functors).

Code:
class NameEqual
{
public:
  // Constructor
  NameEqual(const std::string& name):mName(name){};
  // () operator, makes it possible to call the class
  // as if its a function
  bool operator() (const Country& country) const
  {
    return country.CountryName == mName;
  }
private
  std::string mName;
  
};

class PersonEqual
{
public:
  PersonEqual(const std::string& name):mName(name){};
  bool operator() (const Country& country) const
  {
    return country.PersonsName == mName;
  }
private
  std::string mName;
  
};

class CoordsEqual
{
public:
  CoordsEqual(const std::string& coords):mCoords(coords){};
  bool operator() (const Country& country) const
  {
    return country.Coords == mCoords;
  }
private
  std::string mCoords;
  
};
----------------------------------------
With those classes defined you can do cool things, such as:
Code:
  // Find Country name
  NameEqual nameEqual(&quot;Sweden&quot;);
  CountryVector::iterator it = std::find_if(places.begin(), places.end(),nameEqual);
  if (it == places.end()) { // Not found...etc
  .
  .
  // Find person name
  PersonEqual personEqual(&quot;Foo Bar&quot;);
  it = std::find_if(places.begin(), places.end(),personEqual);
  .
  .
  // Find coord
  CoordsEqual coordsEqual(&quot;10.0N 20.4W&quot;);
  it = std::find_if(places.begin(), places.end(),coordsEqual);

If it seems mysterious, set a breakpoint at a find_if, step in and see what's going on...

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Oh I forgot, perhaps its obvious.
You dont have to actually make local variables (it was just to illustrate clearer whats going on), you could write it shorter, like:
Code:
it = std::find_if(places.begin(), places.end(),CoordsEqual(&quot;10.0N 20.4W&quot;));
etc


/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
#1 this code is a bit above my current level but I think I see what you did.

To me it seems you made a class to do each function but why do I need a class to do that?
 
The code above isn't that bad once you get used to it. It's the best way to use the algorithms like find() that you were trying to use originally.

If you are having trouble understanding it, I guess a method that is sort of simpler is to just use a simple for loop to find the right country. However, I highly recommend learning the algorithms the way PerFnurt has shown, because they are more powerful and easier to use in practice once you understand them (you don't have to write your own loops every time, you can just take advantage of a single algorithm).

So here is an example of what you were trying to do originally but using a for loop instead of the find algorithm. Hope it helps.
Code:
#include <vector>
#include <string>

class Country
{
public:
    std::string     CountryName;
    std::string     PersonsName;
    std::string     Coords;
};

int main()
{
    std::vector<Country> places;

    Country d;
    d.CountryName = &quot;USA&quot;;
    d.PersonsName = &quot;Joe Smyth&quot;;
    d.Coords = &quot;10.0N 20.4W&quot;;
    places.push_back(d);

    std::vector<Country>::const_iterator countryIter = places.begin();
    std::vector<Country>::const_iterator end = places.end();
    for (; countryIter != end; ++countryIter)
    {
        // This line is not necessary but shows you
        // how to get the object from the iterator.
        Country currentCountry = *countryIter;

        if (currentCountry.Coords == &quot;10.0N 20.4W&quot;)
        {
            // do something.
        }
        if (currentCountry.CountryName == &quot;USA&quot;)
        {
            // do something else.
        }
    }
    return 0;
}

As far as why you need a class for each function, that is just how the STL algorithms work.
 
I don't think it would help much in this particular case, but has a lambda function library that makes using tehse algorithms easier. It lets you write code like:

Code:
for_each( c.begin(), c.end(), cout << _1 << &quot;\n&quot; );

which basically generates an unnamed function object to pass to the algorithm. It looks nicer than having to write one function object per operation you want.


The STL also has some tools that make writing function objects easier.
 
>To me it seems you made a class to do each function but why do I need a class to do that?

It the behaves like a function that expects a Courty and returns true for a certain CountryNames etc.

The difference to a &quot;normal&quot; function: How would you tell the function what name to compare with? A global/static variable? Hard coded? With the function objects its simply set in their constructor.

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Courty? Country!

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top