Reputation: 4370
I read the tutorials about the binary and unary functions. I understood the structure of them, but I couldn't imagine in which case I need these functions. Can you give an example for usage of them.
http://www.cplusplus.com/reference/std/functional/unary_function/
http://www.cplusplus.com/reference/std/functional/binary_function/
Upvotes: 12
Views: 8212
Reputation: 17483
std::unary_function and std::binary_function are base structs for creation adaptable function objects. The word adaptable means that they provide necessary typedefs for being used in conjunction with standard function adaptors like std::not1, std::not2, std::bind1st, std::bind2nd.
You may use them every time you need to use your custom function object together with standard function adaptor.
Lets consider some examples (I know, they are artificial. From the other side I hope, that they are rather descriptive).
Example 1.
Suppose you want to print all strings in a vector with their lengths not less than a particular threshold and print them to std::cout.
One might use the next function object:
class LengthThreshold
{
public:
LengthThreshold(std::size_t threshold) : threshold(threshold) {}
bool operator()(const std::string& instance) const
{
return (instance.size() < threshold);
}
private:
const std::size_t threshold;
};
Now the task is pretty simple and can be performed by std::remove_copy_if algorithm:
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
LengthThreshold(threshold)
);
What if you want to use the same function object to print all the strings with their lengths strictly less than the threshold?
The obvious solution we can come up with is the usage of std::not1 function adaptor:
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
std::not1(LengthThreshold(threshold))
);
In fact, the code above won't compile because our LengthThreshold is not adaptable and has no typedefs which are necessary for std::not1.
To make it adaptable we need to inherit from std::unary_function:
class LengthThreshold : public std::unary_function<std::string, bool>
{
// Function object's body remains the same
}
Now our first example works like a charm.
Example 2.
Lets change our previous example. Suppose we don't want to store a threshold inside the function object. In such case we may change the function object from unary predicate to binary predicate:
class LengthThreshold : public std::binary_function<std::string, std::size_t, bool>
{
public:
bool operator()(const std::string& lhs, std::size_t threshold) const
{
return lhs.size() < threshold;
}
};
And make use of std::bind2nd function adaptor:
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
std::bind2nd(LengthThreshold(), threshold)
);
All the examples above intentionally use only C++ 03.
The reason is that std::unary_function and std::binary_function are deprecated since C++ 11 and completely removed from C++ 17.
It happened with the advent of more generalized and flexible functions like std::bind which make inheriting from std::unary_function and std::binary_function superfluous.
Upvotes: 4
Reputation: 224149
Basically, they provide all the typedef
s necessary to allow composition of higher-order functions from unary and binary function objects using function adaptors. For example, this allows using a binary functor where a unary is needed, binding one of the arguments to a literal value:
std::find_if( begin, end, std::bind1st(greater<int>(),42) );
std::bind1st
relies on the functor passed to it to provide those types.
AFAIK the new std::bind
doesn't need them, so it seems in new code you can use std::bind
and do away with them.
Upvotes: 7
Reputation: 133082
These aren't functions, these are classes (structs, actually, but doesn't matter). When you define your own binary functions to use with STL algorithms, you derive them from these classes in order to automatically get all the typedefs.
E.g.
struct SomeFancyUnaryFunction: public std::unary_function<Arg_t, Result_t>
{
Result_t operator ()(Arg_t const &)
{
...
}
};
now you don't need to manually provide the typedefs for argument_type
, result_type
etc. These structs, just like the iterator
struct are there just for our convenience, in order to reuse the typedefs needed for algorithms.
Update for C++11:
As of C++11, the new std::bind
does not really need any typedefs, so there are, in a way, obsolete.
Upvotes: 13
Reputation: 10280
There's an explanation on the sgi STL documentation of Function Objects. In summary, unary_function and binary_function are used to make functors adaptable. This allows them to be used with function object adaptors such as unary_negate.
Upvotes: 6