31

std::binary_function is deprecated now and is going to be deleted in . I searched on different publications, but I couldn't find a exact way to replace it. I'd like to know how should I write the following code in style.

template <class T>
inline T absolute(const T &x) {
    return (x >= 0) ? x : -x;
}

template <class T>
struct absoluteLess : public std::binary_function<T, T, bool> {
    bool operator()(const T &x, const T &y) const {
        return absolute(x) < absolute(y);
    }
};

template <class T>
struct absoluteGreater : public std::binary_function<T, T, bool> {
    bool operator()(T &x, T &y) const {
        return absolute(x) > absolute(y);
    }
};

EDIT

I'm using the functions in the following way:

output[j] = *std::max_element(input.begin() + prev,
                              input.begin() + pos,
                              absoluteLess<float>());

input and output are std::vectors, inside a for-loop.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Luis
  • 433
  • 1
  • 5
  • 11
  • 2
    why you need it? type traits and decltype can figure out the type of `operator()` without the needs of `binary_function` – Bryan Chen Oct 14 '15 at 00:17
  • 2
    How do you use these template functions? The answer depends on the usage. – Rostislav Oct 14 '15 at 00:17
  • 1
    http://stackoverflow.com/a/22863957/642626 thats how you find out the arguments and return type of any callable object. – Bryan Chen Oct 14 '15 at 00:24
  • LLVM C++ standard library still using `binary_function` at the end of 2020 https://github.com/llvm/llvm-project/blob/main/libcxx/include/functional What is more `clang++ --std=c++17` still can compile code which uses `binary_function` https://github.com/llvm/llvm-project/blob/main/libcxx/include/__functional_base – x4444 Dec 29 '20 at 04:34

4 Answers4

21

The only thing std::binary_function does is providing the member typedefs result_type, first_argument_type, and second_argument_type. And the only thing in the standard library that uses these typedefs is std::not2, which is 1) strictly superseded by C++17 std::not_fn, 2) easily replaced by a lambda anyway, and 3) deprecated in C++17 and likely going to be removed in the next revision.

If, for whatever reason, you need to use not2, the legacy binders (bind1st/bind2nd, both deprecated in C++11 and removed in C++17), or some ancient third-party thing following that protocol, the replacement is to define the typedefs directly in your class:

using result_type = bool;
using first_argument_type = T;
using second_argument_type = T;

Otherwise, simply remove the inheritance.

T.C.
  • 133,968
  • 17
  • 288
  • 421
21

First, my advice is to watch CppCon 2015: Stephan T. Lavavej "functional: What's New, And Proper Usage". std::binary_function is mentioned on slide 36, at around 36 mins in the video. You can find the slides at github.com/CppCon/CppCon2015). It doesn't go into detail why you shouldn't use std::binary_function, but if you're using something that's been deprecated since C++11, then you would probably benefit from watching it.

If you want the actual rationale for not using it, try n4190:

unary_function/binary_function were useful helpers when C++98-era adaptors needed argument_type/etc. typedefs. Such typedefs are unnecessary given C++11's perfect forwarding, decltype, and so forth. (And they're inapplicable to overloaded/templated function call operators.) Even if a class wants to provide these typedefs for backwards compatibility, it can do so directly (at a minor cost in verbosity) instead of inheriting from unary_function/binary_function, which is what the Standard itself started doing when these helpers were deprecated.

Now you simply don't need it, so you can remove all traces of it from your program.

In C++14, transparent comparators were added. But it can be implemented in C++11. Just specialize it for void:

template<>
struct absoluteLess<void> {
    template< class T, class U>
    constexpr auto operator()( T&& lhs, U&& rhs ) const
      -> decltype(absolute(std::forward<T>(lhs)) < absolute(std::forward<U>(rhs)))
    {
        return absolute(std::forward<T>(lhs)) < absolute(std::forward<U>(rhs));
    }
}
};

Now the type can be deduced:

std::max_element(v.begin(), v.end(), absoluteLess<>());
user5443145
  • 226
  • 1
  • 2
2

binary_function can easily be replaced by lambda functions:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

// Lambdas can be declared in the global scope
auto absolute = [](auto& x)->float{ return x<0?-x:x;};

int main()
{
    // Lambdas can be declared embedded in functions
    auto absoluteLess = [&](auto&x, auto&y)->bool{ return absolute(x)>absolute(y);};
    auto absoluteGreater = [&](auto&x, auto&y)->bool{ return absolute(x)<absolute(y);};
    
    std::vector<float> input={-2.0, 0.0, 3.4, -123.0};
    std::cout <<  *std::max_element(input.begin(), input.end(), absoluteLess) <<std::endl;
    std::cout <<  *std::max_element(input.begin(), input.end(), absoluteGreater) <<std::endl;

    return 0;
}

Test it online

Adrian Maire
  • 14,354
  • 9
  • 45
  • 85
1

I believe you're looking for std::function.

ulatekh
  • 1,311
  • 1
  • 14
  • 19
  • 2
    It would be nice if you showed how to implement it in the code from the question. – Dharman Feb 17 '20 at 20:57
  • @Dharman: That seemed like overkill... std::function encapsulates anything that behaves like a function, with any number of parameters. – ulatekh Feb 24 '20 at 15:59