Variadic список указателей на данные членов

Рассмотрим этот рабочий код. Функция searchByDataMember использует указатель на член данных в качестве аргумента для поиска значения среди контейнера.

#include <iostream>
#include <list>
#include <string>

template <typename Container, typename T, typename DataPtr>
typename Container::value_type searchByDataMember (const Container& container, const T& t,
DataPtr ptr) {
for (const typename Container::value_type& x : container) {
if (x->*ptr == t)
return x;
}
return typename Container::value_type{};
}

struct Object {
int ID, value;
std::string name;
Object (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};

std::list<Object*> objects { new Object(5,6,"Sam"), new Object(11,7,"Mark"),
new Object(9,12,"Rob"), new Object(2,11,"Tom"), new Object(15,16,"John") };

int main() {
const Object* object = searchByDataMember (objects, 11, &Object::value);
std::cout << object->name << '\n';  // Tom
}

Итак, как распространить вышеприведенное на использование переменного списка указателей на элементы данных в качестве аргументов, если элемент данных, на который указывает сам элемент, имеет элементы данных для поиска? Например,

#include <iostream>
#include <list>
#include <string>

template <typename Container, typename T, typename... DataPtrs>
typename Container::value_type searchByDataMember (const Container& container, const T& t,
DataPtrs... ptrs) {
// What to put here???
}

struct Thing {
int ID, value;
std::string name;
Thing (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};

struct Object {
int rank;
Thing* thing;
Object (int r, Thing* t) : rank(r), thing(t) {}
};

std::list<Object*> objects { new Object(8, new Thing(5,6,"Sam")), new Object(2, new Thing(11,7,"Mark")),
new Object(1, new Thing(9,12,"Rob")), new Object(9, new Thing(2,11,"Tom"))};

int main() {
// The desired syntax.
//  const Object* object = searchByDataMember (objects, 11, &Object::thing, &Thing::value);
//  std::cout << object->thing->name << '\n';  // Tom (the desired output)
}

Так что здесь мы хотим искать среди контейнера objects для Object* это имеет Thing* элемент данных которого value членом данных является 11, который является Object* у которого есть «Том». Не должно быть никаких ограничений в отношении того, насколько большая цепочка указателей на элементы данных может быть передана в searchByDataMember,

0

Решение

Вам нужен способ подать заявку operator ->* в последовательности:

template <typename T, typename MPtr>
auto arrow(T* obj, MPtr mptr)
{
return obj->*mptr;
}

template <typename T, typename MPtr, typename ... MPtrs>
auto arrow(T* obj, MPtr mptr, MPtrs... mptrs)
{
return arrow(obj->*mptr, mptrs...);
}

Тогда ваша функция поиска проста, что-то вроде: (я предпочитаю возвращать итератор над значением btw)

template <typename Container, typename T, typename... DataPtrs>
auto searchByDataMember (const Container& container, const T& t, DataPtrs... ptrs)
{
return std::find_if(std::begin(container), std::end(container),
[&](const auto&e) {
return arrow(e, ptrs...) == t;
});
}

демонстрация

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]