Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Проблема с алгоритмами STL

590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
Делаю класс коллекции типов с возможностью параметрического поиска.
В качестве хранилища использую вектор, в качестве алгоритмов поиска - стандартные алгоритмы STL. В частности find_if.

Вот собственно пример такого класса. Естественно максимально упрощенный. В оригинальном классе используется не int тип, но здесь он для примера.

Код:
//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>

using namespace std;

...

class intCollection
{
        public:
        intCollection()
        {
                for(int i=0; i<50; i++)
                {
                        entities.push_back(random(200));
                }
        }

        int searchInt;

        int searchFirstMatch(int val) //Функция поиска
        {
                this->searchInt=val;
                vector<int>::iterator result;
                result=find_if(entities.begin(), entities.end(), isMatch);
                if(result!=entities.end())
                        return *result;
                else
                        return NULL;
        }
        private:
        vector<int> entities; // Вектор хранилище
        bool isMatch(int val) // Функция проверки совпадения
        {
                return(val==searchInt);
        }
};

...

intCollection test;
test.searchFirstMatch(5);


Собственно ошибка происходит при попытке поиска. Что то компилятору не нравится в ссылке на функцию проверки совпадения.
 
Код:
result=find_if(entities.begin(), entities.end(), [color=red]isMatch[/color]);

Ума не приложу в чем дело...
92
20 декабря 2007 года
Тень Пса
2.2K / / 19.10.2006
а чивой говорит-то?
590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
"И говорит она человечьим голосом..." ©"По щучьему велению" :)...

А говорит вот что:

 
Код:
[C++ Error]_algobase.c(192): E2468 Value of type void is not allowed;
[C++ Error]_algobase.c(192): E2342 Type mismatch in parameter '__pred'(wanted 'void', got 'void');


Т.е. похоже не нравится проге указатель на функцию проверки совпадения. Ток че ей надо не пойму...

Самое интересное, что такая фигня происходит, когда все функции запихнуты в класс. Когда они россыпью в коде, то все нормально... :(
16K
20 декабря 2007 года
HolyDel
11 / / 03.03.2006
может получится через неймспейс класса обратиться?
result=find_if(entities.begin(), entities.end(), intCollection::isMatch);
if
92
20 декабря 2007 года
Тень Пса
2.2K / / 19.10.2006
ну да, или this->isMatch... я думаю должно сканать.
590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
Через this-> попробовал сразу же при возникновении проблемы... Не проканало...

Через namespace тоже :( Не пойму в чем проблема собственно. Вроде как формально все правильно.
320
20 декабря 2007 года
m_Valery
1.0K / / 08.01.2007
Код:
#include <vector>
#include <ctime>
#include <algorithm>
using namespace std;
class intCollection
{
        public:
        intCollection()
        {
                for(int i=0; i<50; i++)
                {
                        entities.push_back(rand() % 100);
                }
        }
        void searchFirstMatch(int val) //Функция поиска
        {
                vector<int>::iterator result;
                result=find(entities.begin(), entities.end(),val);
                if(result != entities.end()){
                    cout<<"This element is found "<<*result<<endl;
                    cout<<"The "<<distance(entities.begin(),result)
                        <<" is the first divisible by "<<*result<<endl;
                    copy(result,entities.end(),
                        ostream_iterator<int>(cout," "));
                    cout<<endl;
                }
                else
                    cout<<"The element : "<<val<<" is not found"<<endl;
        }
        private:
        vector<int> entities; // Вектор хранилище
};
int main()
{
    srand(time(0));
    intCollection test;
    test.searchFirstMatch(5);
   
    return 0;
}

Смотри у Страуструпа на странице 588.Он пишет :
Алгоритмы find,find_if возвпащают итератор для первого элемента, удовлетворяющего значению или предикату соответственно. Фактически,find можно рассматривать как версию find_if с предикатом равно.Почему бы обе эти функции не назвать find ? Прчина в том,что перегрузка функций не всегда различает вызовы двух шаблоных функций с одинаковым числом аргументов...

590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
Алгоритм find работает с цельными типами, т.е. если типом является int, он сравнивает int с int. Если типом является someClass, то сравнивается someClass с someClass. Т.е. find работает как find_if с предикатом равенства.

А мне нужно выяснить равенство не самого класса, а определенных переменных этого класса(полей), для чего я пишу функцию сравнения этих полей (isMatch).
По этому и нужен find_if. Но указатель на функцию предиката не хочет восприниматься внутри find_if, если алгоритм выполняется внутри класса. Если все функции вне класса расписать, то работает. (!?)

За примерчик спасибо, но не совсем то...


Кажется ситуация начинает немного проясняться... Похоже виной всему некоторые косяки с получением адреса внутриклассовой функции.

Код:
class intCollection
{
        public:
        intCollection()
        {
                for(int i=0; i<50; i++)
                {
                        entities.push_back(random(200));
                }
        }

        int searchInt;

        int searchFirstMatch(int val) //Функция поиска
        {
                this->searchInt=val;
                vector<int>::iterator result;
                [color=red]bool (*p)(int);//создаем указатель на функцию типа isMatch
                //Дальше самое интересное...
                p=isMatch; //Казалось бы здесь p должен присваиваться адрес функции isMatch, однако компилятор ругается и не хочет этого делать. p=this->isMatch; дает аналогичный результат.
                [/color]
                result=find_if(entities.begin(), entities.end(), isMatch);
                if(result!=entities.end())
                        return *result;
                else
                        return NULL;
        }
        private:
        vector<int> entities; // Вектор хранилище
        bool isMatch(int val) // Функция проверки совпадения
        {
                return(val==searchInt);
        }
};
361
20 декабря 2007 года
Odissey_
661 / / 19.09.2006
Ну а если посмотреть на определение -
 
Код:
template <class InputIterator, class Predicate>
InputIterator find_if(InputIterator first, InputIterator last,
                      Predicate pred) {
  while (first != last && !pred(*first)) ++first;
  return first;

Разве методом класса можно определить шаблон?
В стандарте прописано что предикат - "This function object may be a pointer to function, or an object of a type with an appropriate function call operator.". То есть, если я правильно понял, это или самостоятельная функция или объект.
590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
Ну а в чем собственно разница между внутренней функцией класса и внешней функцией? Т.е. в чем разница для шаблона? Написано явно "This function object may be a pointer to function". Какой функцией не описано.

Тут ИМХО проблема с указателем на внутреннюю функцию класса.

Функция isMatch имеет вид bool (int). Указатель для нее определяется как
 
Код:
bool (*p) (int)
. Но вот запись
 
Код:
p=isMatch
внутри класса не работает!? В общем похоже тут надо копать в направлении указателей на внутренние функции класса.
361
20 декабря 2007 года
Odissey_
661 / / 19.09.2006
Так я ж вам про то и говорю. IsMatch имеет тип bool (intCollection:: ) (int) , а не bool (*)(int).
590
20 декабря 2007 года
Gigahard
223 / / 03.04.2006
Решение? Делать внешние friendly функции?

P.S. Получается, никак кроме
 
Код:
bool(intCollection::*p)(int);
p=&intCollection::isMatch;
указатель на внутреннюю функцию класса не сделать?
361
20 декабря 2007 года
Odissey_
661 / / 19.09.2006
Со стандартным find_if видимо нет, он незнает ничего об объекте вашего класса. Но вот если написать так например -
Код:
#include <vector>
#include <algorithm>

class IntTest;

template <class InputIterator, typename Predicate, class Object>
InputIterator obj_find_if(InputIterator first, InputIterator last,
                      Predicate pred, Object * obj) {
  while (first != last && !(obj->*pred)(*first)) ++first;
  return first;}

typedef bool (IntTest::* comparator)(int) ;

class IntTest
{
    private:
        int     search;
        std::vector<int> data;
        bool isMatch (int t){if (t==search) return true; return false;};
    public:
        IntTest()
            {
                for(int i=0; i<10; ++i)
                    data.push_back(i);
            };
        int find(int _search)
            {
                search = _search;
                comparator comp = &IntTest::isMatch;
                std::vector<int>::iterator result;
                result=obj_find_if(data.begin(), data.end(), comp, this);
                if (result!=data.end())
                    return *result;
                else
                    return -1;                 
            };
};



int main()
{
    IntTest test;
    int rez = test.find(5);
    std::cout << rez << std::endl;
    rez = test.find(11);
    std::cout << rez << std::endl;
    return 0;
}
3
20 декабря 2007 года
Green
4.8K / / 20.01.2000
Цитата: Gigahard
Делаю класс коллекции типов с возможностью параметрического поиска.
В качестве хранилища использую вектор, в качестве алгоритмов поиска - стандартные алгоритмы STL. В частности find_if.

Вот собственно пример такого класса. Естественно максимально упрощенный. В оригинальном классе используется не int тип, но здесь он для примера.

Код:
//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>

using namespace std;

...

class intCollection
{
        public:
        intCollection()
        {
                for(int i=0; i<50; i++)
                {
                        entities.push_back(random(200));
                }
        }

        int searchInt;

        int searchFirstMatch(int val) //Функция поиска
        {
                this->searchInt=val;
                vector<int>::iterator result;
                result=find_if(entities.begin(), entities.end(), isMatch);
                if(result!=entities.end())
                        return *result;
                else
                        return NULL;
        }
        private:
        vector<int> entities; // Вектор хранилище
        bool isMatch(int val) // Функция проверки совпадения
        {
                return(val==searchInt);
        }
};

...

intCollection test;
test.searchFirstMatch(5);


Собственно ошибка происходит при попытке поиска. Что то компилятору не нравится в ссылке на функцию проверки совпадения.
 
Код:
result=find_if(entities.begin(), entities.end(), [color=red]isMatch[/color]);

Ума не приложу в чем дело...



Ну в чем дело тебе уже рассказали.
Расскажу, что делать. Но сначала поругаю. :)

Какое отношение searchInt имеет к классу intCollection ?
Ответ: никакого!
Тогда какого такое поле существует в этом классе?
Вывод: не захламляйте классы не нужными полями.

Теперь, как решить проблему.
На столько просто, что просто приведу код:

Код:
int searchFirstMatch(int val) //Функция поиска
        {
            class Comparator {
            public:
                Comparator(int searchInt) :searchInt(searchInt) {}

                bool operator()(int val) {
                    return (val == searchInt);
                }

            private:
                int searchInt;
            };

            vector<int>::iterator result;
            result = find_if(entities.begin(), entities.end(), Comparator(val));


Еще немного бурчания.
Как ты определяешь, удачно ли закончился поиск?
Если ты будешь искать нулевое значение, то ты не узнаешь нашел ты его или нет.
Я бы возвращал, в зависимости от остального кода программы, либо bool, либо итератор, либо прокси-объект.
590
21 декабря 2007 года
Gigahard
223 / / 03.04.2006
Ну, если мы используем в качестве предиката функцию, то переменная searchInt необходима для передачи искомого значения в предикат. Ведь прототип функции предиката должен иметь только один аргумент.

Ща Ваш вариант попробую :)

Заработало. Кстати... Класс компаратора объявляется вне функции?

Как ты определяешь, удачно ли закончился поиск?
Если ты будешь искать нулевое значение, то ты не узнаешь нашел ты его или нет.

int в данном случае для примера. Никаких проверок. В будущем классе нулевых объектов не будет. По этому ноль и будет сигналом ошибки.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог