Вопрос

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

#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&)'
Это было полезно?

Решение

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

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()).Помните, что если вы берете объект функции по константной ссылке, вы, как правило, не можете его скопировать, поскольку пользователь мог передать функцию.При его копировании будет предпринята попытка локально объявить функцию вместо указателя на локальную функцию.Однако при принятии по значению вместо этого будет принят указатель на функцию, когда функция была передана, и его можно безопасно скопировать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top