简体   繁体   中英

stl predicate with different types

I have a vector of ordered container classes where I need to know the index of the container that has a given element

so, I would like to do the following, but this obviously doesn't work. I could create a dummy Container to house the date to find, but I was wondering if there was a nicer way.

struct FooAccDateComp 
{
  bool operator()(const Container& d1, const MyDate&  f1) const 
  { return   d1->myDate < f1; } 
};

class Container
{
   MyDate myDate;
   ...
};

vector<Container> mystuff; 
MyDate temp(2008, 3, 15);

//add stuff to variable mystuff

int index = int(upper_bound(events.begin(), events.end(),temp, FooAccDateComp())-events.begin());

EDIT: The container class can contain other dates.

upper_bound needs to be able to evaluate expressions like Comp(date,container) , but you've only provided Comp(container,date) . You'll need to provide both:

struct FooAccDateComp 
{
    bool operator()(const Container& c, const MyDate& d) const 
        { return c.myDate < d; } 

    bool operator()(const MyDate& d, const Container& c) const 
        { return d < c.myDate; } 
};

Remember that the vector must be sorted according to this comparison for upper_bound and friends to work.

You don't necessarily need a special predicate, just enable comparison between Container and MyDate.

#include <vector>

struct MyDate {
   MyDate(int, int, int);
};

struct Container {
   MyDate myDate;
};

// enable comparison between Container and MyDate
bool operator<(Container const&, MyDate const&);
bool operator==(Container const&, MyDate const&);

std::vector<Container> v; 
//add stuff to variable mystuff
MyDate temp(2008, 3, 15);
std::vector<Container>::iterator i = std::lower_bound(v.begin(), v.end(), temp);
ptrdiff_t index = i != v.end() && *i == temp ? i - v.begin() : -1;

You can use find_if if you don't mind degrading performance (you said that you have a vector of sorted Container , so binary search would be faster) Or you can add

struct Container {
    MyDate myDate;
    operator MyDate () {return myDate}; 
}
bool operator <(MyDate  const&, MyDate const&)
{
  return // your logic here
};    

Now you can use binary search functions

std::vector<Container>::iterator i = std::upper_bound(v.begin(), v.end(), MyDateObject);

Surely, it will work only if your vector is sorted by Container.myDate

Your example is broken in several trivial ways: the class Container should be defined before FooAccDateComp in order for it to be used there, you should make myDate a public member of Container , access that member in the comparison method using .myDate rather than ->myDate , and finally decide whether to call your vector mystuff or events , but not mix both. I'll suppose that appropriate corrections have been made.

You should have defined your comparison function to take a Date parameter as first argument and a Container parameter as second; the opposite to what you did. Or you could use std::lower_bound instead of std::upper_bound if that would suit you purpose (since you don't say what you are going to do with index it is hard to tell) as the choice made in the question is adapted to that. Contrary to what the currently accepted answer says you do not need both if you are only using std::upper_bound or only std::lower_bound (though you would need both if using std::equal_range , or when using both std::upper_bound and std::lower_bound ).

You can find these at first sight a bit strange specifications in the standard, but there is a way to understand without looking it up why they have to be like this. When using lower_bound , you want to find the point that separates the Container entries that are (strictly) less than your given Date from those that are not, and this requires calling the comparison function with that Date argument in second position. If however you ask for an upper_bound (as you are), you want to find the point that separates the entries that are not strictly greater than your given Date from those that are, and this requires calling the comparison function with that Date argument in first position (and negating the boolean result it returns). And for equal_range you of course need both possibilities.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM