2010-08-20 4 views
2

У меня есть вектор упорядоченных контейнерных классов, где мне нужно знать индекс контейнера, который имеет данный элементСТЛ сказуемое с различными типами

так, я хотел бы сделать следующее, но это, очевидно, Безразлично» т работы. Я мог бы создать фиктивный контейнер для размещения даты, чтобы найти, но мне было интересно, был ли более приятный способ.

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: Класс контейнера может содержать другие даты.

+1

Измените upper_bound на find_if, и он должен работать нормально. Тем не менее, почему вы не используете карту здесь? –

+0

@Billy: отсортированный вектор может быть быстрее карты, если вы не меняете его очень часто. –

+2

@Billy: сложности различны, 'upper_bound' - O (log N), а' find_if' - O (N). –

ответ

4

upper_bound должен уметь оценивать выражения типа Comp(date,container), но вы указали только Comp(container,date). Вы должны будете предоставить как:

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; } 
}; 

Помните, что вектор должен быть отсортирован в соответствии с этим сравнением для upper_bound и друзей, чтобы работать.

+1

Gasp, вы были быстрее: p Я просто хотел добавить, что 'upper_bound' не обязательно возвращает' Container' с указанной датой, он возвращает первый элемент с датой равным OR GREATER. После этого вам нужно будет протестировать, если вы достигнете конца и (если нет), если дата действительно то, что вы хотели (в векторе может не быть такого контейнера). –

+0

Я пробовал это, и он все еще жалуется на то, что не смог «преобразовать параметр 2 из const Container & to const Date &». Я использую VS2008. Это работает с вашей стороны? Я согласен, что он должен работать – Steve

+0

@Steve: Я сделал быстрый тест с GCC, прежде чем отвечать, и все было в порядке. Боюсь, у меня нет копии VS. –

1

Вам не обязательно нужен специальный предикат, просто укажите сравнение между контейнером и 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; 
+1

Исходный предикат намного лучше, на самом деле. Рассмотрим случай, когда у вас есть несколько дат в «Контейнере», с чем вы бы сравнили? –

+0

Добавьте сложность, только если вам нужно. В этом примере это кажется ненужным. –

+0

На самом деле в контейнере есть другие даты. Я обновлю вопрос – Steve

0

Вы можете использовать find_if, если вы не против снижения производительности (вы сказали, что у вас есть вектор отсортированный Container, поэтому бинарный поиск будет быстрее) Или вы можете добавить

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

Теперь вы можете использовать бинарные функции поиска

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

Конечно, это будет работать только если ваш вектор сортируется по Container.myDate

+1

Я предполагаю, что вы имеете в виду 'operator MyDate()'. Обычно лучше избегать операторов преобразования, если это возможно; они могут маскировать ошибки, которые в противном случае были бы уловлены компилятором. Кроме того, это дает ненужную копию при каждом сравнении. –

+0

Да, мой плохой. Это определенно должен был быть 'operator MyDate()'. Исправлена. Спасибо за указание на это – a1ex07

0

Ваш пример сломан в нескольких тривиальных способах: класс Container должен быть определен до того FooAccDateComp для того, чтобы использовать его там, вы должны сделать myDateобщественного члена Container, доступ к этому члену в методе сравнения с использованием , а не ->myDate, и, наконец, решить, назовите ваш вектор mystuff или events, но не смешайте оба. Я полагаю, что были сделаны соответствующие исправления.

Вы должны были определить свою функцию сравнения, чтобы принять в качестве первого аргумента параметр Date и параметр Container как второй; напротив того, что вы сделали. Или вы можете использовать std::lower_bound вместо std::upper_bound, если это вам подойдет (поскольку вы не говорите, что вы собираетесь делать с index, это трудно сказать), так как выбор, сделанный в вопросе, адаптирован к этому. Вопреки тому, что в настоящее время принятый ответ говорит, что вам не нужны оба, если вы используете только std::upper_bound или только std::lower_bound (хотя вам понадобятся и то, и другое, если используете std::equal_range, либо при использовании как std::upper_bound, так и std::lower_bound).

Вы можете найти их на первый взгляд немного странные спецификации в стандарте, но есть способ понять, не глядя, почему они должны быть такими.При использовании lower_bound вы хотите найти точку, которая отделяет записи Container, которые (строго) меньше, чем ваши данные Date от тех, которые не являются, и для этого требуется вызвать функцию сравнения с аргументом во второй позиции. Если, однако, вы запрашиваете upper_bound (как и вы), вы хотите найти точку, которая отделяет записи не строго больше, чем ваши данные Date от тех, которые есть, и для этого требуется вызвать функцию сравнения с этим аргументом Date в первой позиции (и отрицает возвращаемый логический результат). А для equal_range вам, разумеется, нужны обе возможности.