Skip to main content
gamedev.net
🔒 Locked

binary functions

Started by daniel_i_l 2 replies 600+ views
Original Post
daniel_i_l
daniel_i_l
I don't understand how deriving classes from binary_function:

#include <functional>
template<class Arg1, class Arg2, class Result>
       struct binary_function {
       typedef Arg1 first_argument_type;
       typedef Arg2 second_argument_type;
       typedef Result result_type;
       };

and giving them a () operator makes them behave as a function pointer (that gets two inputs and returns an output). Could someone explain? Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
deffer
deffer
Your class doesn't need to be derived from binary_function to have a working () operator.

That said, library writers might want to "know" what types is your function/functor operating on/returning. So they are asking for embeeded typedefs of your class - result_type, first_argument_type, etc. It is true that you could define the necessary types yourself, but there are more tricks that are possible only by deriving from a fixed class that everybody use.

For example, library writers might want to do some nifty tricks based on function's arity:

template< typename Functor >void do_unary_or_binary(MyClass & obj, Functor f){  if (/*f is unary*/)    f(obj);  else if (/*f is binary*/)    f(obj, some_other_obj);};


This will probably crash miserably, if f could not be called with one parameter AND with two parameters.

You can use overloading to make do_unary_or_binary work, knowing base class of the functor. (No, template specialisation will not work here at all.)

struct unary_tag {};struct binary_tag {};template<class Arg1, class Result>unary_tag  get_function_tag(const unary_function<Arg1,Result> &){  return unary_tag(); };template<class Arg1, class Arg2, class Result>binary_tag  get_function_tag(const binary_function<Arg1,Arg2,Result> &){  return binary_tag(); };template<class Arg1, class Result>unary_tag  get_function_tag( Result (*f)(Arg1) ){  return unary_tag(); };template<class Arg1, class Arg2, class Result>binary_tag  get_function_tag( Result (*f)(Arg1,Arg2) ){  return binary_tag(); };template< typename Functor >void do_unary_or_binary_impl(MyClass & obj, Functor f, unary_tag){  // can safely assume Functor is unary.  f(obj);};template< typename Functor >void do_unary_or_binary_impl(MyClass & obj, Functor f, binary_tag){  // can safely assume Functor is binary.  f(obj, some_other_obj);};template< typename Functor >void do_unary_or_binary(MyClass & obj, Functor f){  do_unary_or_binary_impl(obj, f, get_function_tag(f));};
Vorpy
Vorpy
The thing that makes a function object behave as a function is just overloading operator(). operator() is just like any other operator or method a class can overload; it just happens to make calling the method use the same syntax as is used for calling a function.

The standard library's template algorithms (and similiar generic code) sometimes need to know the types that operator() uses. unary_function and binary_function provide standard names for the types and a concise way to define them (by inheriting from unary_function or binary_function with the types declared as the template parameters).
Telastyn
Telastyn
They don't behave as a function pointer. Indeed, if you try to pass them to a function pointer you'll get errors (pretty sure anyways). They can however be called identically to common functions, so when passed into a template, the glorified string-replacement produces still-functional code.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.