Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a function object: Error

What's wrong with the following little program that passes a function object?

#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;
}

I'm getting the following error in line 6:

 no match for call to 
`(const std::unary_function<const std::string&, void>) (const std::string&)'
like image 261
Frank Avatar asked Dec 18 '22 08:12

Frank


1 Answers

A common mistake. unary_function and binary_function are just two structs that add typedefs

argument_type
result_type

and respectively

first_argument_type
second_argument_type
result_type

Not more. They are for convenience of creators of function object types, so they don't have to do those themselves. But they don't behave polymorphic. What you want is function object wrapper. boost::function comes to mind:

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

Or make it a template

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

You can take it by value and then return the copy from foo if use it to apply it to some sequence. Which would allow the function object to update some state variables among its members. for_each is an example that does it like that. Generally, anyway, i would accept them by value because they are usually small and copying them allows greater flexibility. So i do

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

You will then be able to take a copy of fct and save it somewhere, and fct's operator() can be non-const and update some members (which is part of the whole point of operator()). Remember if you take a function object by const reference, you can't generally copy it, because the user could have passed a function. Copying it then will try to locally declare a function instead of a local function pointer. However, accepting by-value will accept a function pointer instead when a function was passed, which can safely be copied.

like image 159
Johannes Schaub - litb Avatar answered Dec 29 '22 22:12

Johannes Schaub - litb