What to do about std::binary_function and std::unary_function?
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
[Nick Matteo]
std::binary_function and std::unary_function are deprecated, and scheduled to be removed from the standard in C++17.
With VS 2015, you can verify that your code isn't using this stuff by defining _HAS_AUTO_PTR_ETC to 0 (ideally on the command line). STL
On 05.05.2016 21:18, Nick Matteo wrote:
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>.
3a) Provide boost::binary_function<Arg1, Arg2, Result>, which inherits std::binary_function<Arg1, Arg2, Result> if it is available, and reimplements std::binary_function otherwise. This seems like the least intrusive, most backwards-compatible solution. Any old code that (for some pathological reason) depends on the use of std::binary_function will continue to function so long as std::binary_function exists. Any code that merely depends on the typedefs that std::binary_function provides will continue to function indefinitely. All existing boost code can be updated with a simple search-and-replace, with no decrease in code readability or compactness. And moving from (3a) to (3) would be a simple change to a single file, should this change ever become necessary or desirable. -- Rainer Deyke (rainerd@eldwood.com)
On 6 May 2016 at 03:32, Rainer Deyke <rainerd@eldwood.com> wrote:
On 05.05.2016 21:18, Nick Matteo wrote:
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>.
3a) Provide boost::binary_function<Arg1, Arg2, Result>, which inherits std::binary_function<Arg1, Arg2, Result> if it is available, and reimplements std::binary_function otherwise.
I disagree. The standard is getting rid of them for good reason. Boost should too. -- Nevin ":-)" Liber <mailto:nevin@cplusplusguy.com <nevin@eviloverlord.com>> +1-847-691-1404
On Fri, May 6, 2016 at 4:32 AM, Rainer Deyke <rainerd@eldwood.com> wrote:
3a) Provide boost::binary_function<Arg1, Arg2, Result>, which inherits std::binary_function<Arg1, Arg2, Result> if it is available, and reimplements std::binary_function otherwise.
This would need some sort of macro to tell us if std::binary_function is available. I looked into whether any SD-6 feature test macros were being suggested for this. Last year they were considering either __cpp_lib_removed_function_objects or __cpp_lib_removed_deprecated_functionals (https://www.mail-archive.com/features@isocpp.open-std.org/msg00114.html). But ultimately they decided not to provide any macros for this in the current version (23 Feb 2016) at https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendat.... (The relevant row is N4190, listing _none_.) The justification was somehow left out of that page, but can be seen at https://www.mail-archive.com/features%40isocpp.open-std.org/msg00198.html#de... : "These library features are removed because superior alternatives to them were introduced in C++11. Because these alternatives are superior, there is little motivation to maintain code that uses one of these obsolescent features when it is available." So, it seems that Study Group 10 is essentially recommending option 4. -- Nick Matteo
Nick Matteo wrote:
2) Remove the inheritance from std::binary_function, and add the typedefs. 4) Just remove inheritance from std::binary_function (and don't provide typedefs.)
Either one of those would be fine, although I personally would do something in-between and only provide result_type for boost::bind, mostly out of nostalgia. :-)
On Fri, May 6, 2016 at 5:36 PM, Peter Dimov <lists@pdimov.com> wrote:
Either one of those would be fine, although I personally would do something in-between and only provide result_type for boost::bind, mostly out of nostalgia. :-)
Shouldn't boost::bind be updated to use std::result_of instead? (That is, #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL from Boost.Config.) Nick Matteo
participants (5)
-
Nevin Liber
-
Nick Matteo
-
Peter Dimov
-
Rainer Deyke
-
Stephan T. Lavavej