Передача функционального объекта: ошибка - PullRequest
4 голосов
/ 29 марта 2009

Что не так со следующей маленькой программой, которая передает функциональный объект?

#include <iostream>
#include <functional>

void foo(const std::unary_function<const std::string&, void>& fct) {
  const std::string str = "test";
  fct(str); // error
}

class MyFct : public std::unary_function<const std::string&, void> {
public:
  void operator()(const std::string& str) const {
    std::cout << str << std::endl;
  }
};

int main(int argc, char** argv){
  MyFct f;
  foo(f);
  return 0;
}

Я получаю следующую ошибку в строке 6:

 no match for call to 
`(const std::unary_function<const std::string&, void>) (const std::string&)'

1 Ответ

11 голосов
/ 29 марта 2009

Распространенная ошибка. unary_function и binary_function - это всего лишь две структуры, которые добавляют typedefs

argument_type
result_type

и соответственно

first_argument_type
second_argument_type
result_type

Не более. Они для удобства создателей типов функциональных объектов, поэтому им не нужно делать это самим. Но они не ведут себя полиморфно. То, что вы хотите, это обертка объекта функции. boost::function приходит на ум:

void foo(boost::function<void(const std::string&)> const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Или создайте шаблон

template<typename FunctionObject>
void foo(FunctionObject const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Вы можете взять его по значению, а затем вернуть копию из foo, если используете ее для применения к некоторой последовательности. Что позволило бы объекту функции обновить некоторые переменные состояния среди его членов. for_each пример, который делает это так. В общем, в любом случае, я бы принял их по значению, потому что они, как правило, маленькие, и их копирование обеспечивает большую гибкость. Так что я делаю

template<typename FunctionObject>
void foo(FunctionObject fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

После этого вы сможете взять копию функции fct и сохранить ее где-нибудь, а оператор fct () может быть неконстантным и обновлять некоторые элементы (что является частью всего пункта operator()) , Помните, что если вы берете объект функции по константной ссылке, вы обычно не можете скопировать его, потому что пользователь мог передать функцию. Затем, копируя его, вы попытаетесь локально объявить функцию вместо указателя на локальную функцию. Однако принятие by-value примет функцию указателя вместо того, чтобы передать функцию, которую можно безопасно скопировать.

...