Параметризовать функцию обратного вызова - PullRequest
1 голос
/ 07 мая 2019

Я создал словарь с функцией обхода, которая принимает обратный вызов для каждого пройденного узла.

Подпись:

void traverse(void visit(ItemType&)) const;

Реализация:

template < class KeyType, class ItemType>
void HashedDictionary< KeyType, ItemType>::traverse(void visit(ItemType&)) const {
    HashedEntry<KeyType, ItemType> *currPtr;
    for (int i = 0; i < hashTableSize; i++) {
        currPtr = hashTable[i];
        while (currPtr != nullptr) {
            ItemType currItem = currPtr->getItem();
            visit(currItem);
            currPtr = currPtr->getNext();
        }
    }
}

В настоящее время я использую этот обратный вызов

void visit(Person& p) {
    cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
}

d->traverse(visit);

Однако я хотел бы добавить параметр для месяца, где имя печатается только в том случае, если месяц является определенным значением.

Как я могу передать месяц этой функции?Что-то с эффектом:

d->traverse(visit(4));

за 4-й месяц ...

Ответы [ 3 ]

2 голосов
/ 07 мая 2019

Как я могу передать месяц этой функции?

В его нынешнем виде вы не можете. Ваш прототип для траверса:

void traverse(void visit(ItemType&)) const;

Если, однако, это выглядело больше как:

template<typename TraverseFunc>
void traverse(TraverseFunc& visit) const;

Тогда вы можете заменить свою функцию функциональным объектом, т.е.

struct MyVisitor {
   int month;
   MyVisitor(int month) : month(month) {}
   // overload () operator
   void operator () (ItemType& item) {
     // do thing to item
   }
};

И тогда вы сможете сделать:

d->traverse(MyVisitor(4));
1 голос
/ 07 мая 2019

Вы можете объявить свой метод traverse() для принятия любого вызываемого типа для посетителя, например:

template < class KeyType, class ItemType, class VisitorType >
void HashedDictionary< KeyType, ItemType>::traverse(VisitorType visit) const {
    HashedEntry<KeyType, ItemType> *currPtr;
    for (int i = 0; i < hashTableSize; i++) {
        currPtr = hashTable[i];
        while (currPtr) {
            ItemType currItem = currPtr->getItem();
            visit(currItem);
            currPtr = currPtr->getNext();
        }
    }
}

Затем вы можете передать функтор или функцию, например:

struct visit {
    int month;
    visit (int mon) : month(mon) {}
    void operator()(Person& p) {
        if (p.getMonth() == month) {
            cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
        }
    }
};

d->traverse(visit(4));
void visitIfApril(Person& p) {
    if (p.getMonth() == 4) {
        cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
    }
}

d->traverse(visitIfApril);
template<const int month>
void visitIf(Person& p) {
    if (p.getMonth() == month) {
        cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
    }
}

d->traverse(visitIf<4>);

В C ++ 11 и более поздних версиях вы также можете передать лямбду вместо:

d->traverse(
    [](Person& p) {
        if (p.getMonth() == 4) {
            cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
        }
    }
);

Альтернативой является предоставление traverse() дополнительного пользовательского параметра для последующей передачи в функцию обратного вызова, например:

template < class KeyType, class ItemType, class UserType >
void HashedDictionary< KeyType, ItemType>::traverse(void visit(ItemType&), UserType user) const {
    HashedEntry<KeyType, ItemType> *currPtr;
    for (int i = 0; i < hashTableSize; i++) {
        currPtr = hashTable[i];
        while (currPtr) {
            ItemType currItem = currPtr->getItem();
            visit(currItem, user);
            currPtr = currPtr->getNext();
        }
    }
}

void visit(Person& p, int month) {
    if p.getMonth() == month) {
        cout << p.getName() << ": " << p.getMonth() << "/" << p.getDay() << "/" << p.getYear() << endl;
    }
}

d->traverse(visit, 4);
0 голосов
/ 07 мая 2019

Вам необходимо передать указатель на функцию, а также все параметры, необходимые для функции, передаваемой в качестве параметра. Так что в вашем случае вы должны передать month в качестве параметра функции traverse.

Подпись:

void traverse(void visit(ItemType&), int month) const;

visit() функция должна иметь параметр month:

void visit(Person& p, int month);

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

d->traverse(visit, 4);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...