Ошибка компиляции C ++ при передаче функции в remove_if - PullRequest
6 голосов
/ 15 апреля 2010

Итак, вот фрагмент моего кода.


void RoutingProtocolImpl::removeAllInfinity()
{
  dv.erase(std::remove_if(dv.begin(), dv.end(), hasInfCost), dv.end()); 
}

bool RoutingProtocolImpl::hasInfCost(RoutingProtocolImpl::dv_entry *entry)
{
  if (entry->link_cost == INFINITY_COST)
  {
    free(entry);
    return true;
  }
  else
  {
    return false;
  }
}

Я получаю следующую ошибку при компиляции:

<code>
RoutingProtocolImpl.cc:368: error: argument of type <code>bool (RoutingProtocolImpl::)(RoutingProtocolImpl::dv_entry*)' does not match</code>bool (RoutingProtocolImpl::<em>)(RoutingProtocolImpl::dv_entry</em>)'

Ответы [ 2 ]

11 голосов
/ 15 апреля 2010

Проблема

Ваш предикат RoutingProtocolImpl::hasInfoCost() является функцией-членом. Алгоритмы STL глупы тем, что могут работать только с вещами, которые напоминают обычные функции. Все алгоритмы STL, которые принимают операцию или предикат в качестве параметра, вызывают их как функцию:

op();

Это прекрасно работает для объектов функций, указателей на обычные функции и указателей на статические члены. В случае функций-членов ссылочных объектов (объектов, созданных в стеке во внешней области действия алгоритма) или функций-указателей на объекты, функция принимает объект, к которому нужно обращаться:

obj.mf();   // reference member function
pobj->mf(); // pointer member function

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

Опция свободных функций

Перевести функцию-член в свободную функцию. Если функция должна работать в контексте какого-либо объекта, передайте этот объект в качестве дополнительного параметра:

bool hasInfCost(RoutingProtocolImpl::dv_entry *entry,
                const RoutingProtocolImpl& o);

Затем, когда вы передадите эту функцию в качестве ссылки на алгоритм STL, вам придется привязать параметр объекта:

for_each(cont.begin(), cont.end(),
         bind2nd(hasInfoCost, RoutingProtocolImpl());

Опция статического члена

Изменить функцию-член, чтобы она была статической функцией-членом. Затем вы можете передать ссылку на него с помощью RoutingProtocolImpl::hasInfoCost. Не имеет смысла заставлять функцию принимать дополнительный параметр типа инкапсулирующего класса. Если он должен работать в контексте объекта, то он не должен быть статичным: либо преобразуйте его в свободную функцию (связанную с ограничениями видимости RoutingProtocolImpl, тем самым способствуя развязке в вашем коде); или используйте метод подшивки и адаптера.

Вариант подшивки и адаптера

Используйте связыватель и адаптер из STL для адаптации функции-члена к чему-то, с чем могут работать алгоритмы STL:

dv.erase(remove_if(dv.begin(), dv.end(),
                   bind1st(mem_fun(&RoutingProtocolImpl::hasInfCost),
                           this)),
         dv.end());

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

Если вы выберете этот путь, убедитесь, что вы правильно поняли константность: если функции-члену не нужно изменять объект, пометьте его как константную функцию. Таким образом, вы сможете вызывать его с помощью временных и постоянных объектов, которые вы передаете в алгоритмы.

5 голосов
/ 15 апреля 2010

Проблема в том, что это: bool RoutingProtocolImpl::hasInfCost(...) является нестатической функцией-членом .

Требуется экземпляр класса для вызова, ala: obj->hasInfCost(...). Однако remove_if не заботится и пытается назвать его как hasInfCost(...). Это несовместимо.

Что вы можете сделать, это сделать static:

static bool RoutingProtocolImpl::hasInfCost(RoutingProtocolImpl::dv_entry *entry) Для этого больше не требуется экземпляр класса для вызова. (У него нет переменных-членов, нет указателя this и т. Д.). Его можно рассматривать как «нормальную» функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...