Boost logo

Boost :

Subject: [boost] What to do about std::binary_function and std::unary_function?
From: Nick Matteo (boost_at_[hidden])
Date: 2016-05-05 15:18:35


std::binary_function and std::unary_function are deprecated, and
scheduled to be removed from the standard in C++17. That means it's
possible that code using these might soon fail to compile when
targeting this standard.

These are still used throughout Boost, including by the libraries
Accumulators, Algorithm, Bimap, Function, Functional, GIL, Graph, ICL,
MPI, Polygon, and Xpressive. You can see all the uses I found in the
1.61 beta boost/ directory at
http://kundor.github.io/ubinary_function_list.html .

All that these classes do are provide the typedefs result_type, and
argument_type (for unary_function) or first_argument_type and
second_argument_type (for binary_function).
In particular, they do not include a virtual operator(), so that one
cannot accept a function object polymorphically as a
std::binary_function&, for example.

So, although it is conceivable that C++98-era user code might check
for inheritance from std::binary_function, it seems rather unlikely:
practically all uses should just depend on the typedefs being present
(which is what the standard library has always done).

With modern C++ standards, the availability of std::result_of,
decltype, and std::function make these typedefs redundant, and
references to them are being phased out of the standard library
(starting with deprecation.)

It seems to me that there are four main possibilities for removing
these classes from Boost. (I'll talk about binary_function in the
following, but it all applies equally to unary_function.)

1) Add some sort of compatibility macro to Boost.Config, to enable
classes to inherit from std::binary_function if it is available, or
add the appropriate typedefs if it is not.

I don't think this is necessary.

2) Remove the inheritance from std::binary_function, and add the typedefs.

This seems to be the default approach: it is used by the C++11
standard itself, and has also already been done by some Boost
libraries, e.g. in container/string.hpp and in
intrusive/priority_compare.hpp.

The drawback here is increased verbosity. Instead of writing

    template <class T>
    struct functor : std::binary_function<T, T, bool> {...};

 We must write

    template <class T>
    struct functor {
       typedef T first_argument_type;
       typedef T second_argument_type;
       typedef bool result_type;
       ...
    };

3) A modification of approach 2: instead of manually adding the
typedefs everywhere, make a base class to provide the typedefs
somewhere in Boost. Then replace inheritance from
std::binary_function<Arg1, Arg2, Result> with inheritance from
boost::binary_function<Arg1, Arg2, Result>.

4) Just remove inheritance from std::binary_function (and don't
provide typedefs.)

This is the bold approach. The typedefs are redundant now: I think the
only use in the standard library is by the deprecated
std::not1/std:not2 and the deprecated binders
std::bind1st/std::bind2nd (which are to be removed in C++17).

This is the direction that the standard library is starting to head,
with all uses of the typedefs deprecated and probably eventually
removed, and even the provision of the typedefs optional in C++17
standard library function objects.

This has already been done at least by Boost Interprocess in detail/mpl.hpp.

Probably the best options are either (2) or (4). Should there be a
default policy on what authors should do?

Nick Matteo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk