Why std::function works as an argument to std::not2?

Viewed 94

std::not2 is implemented in the following way:

template <class Predicate>
binary_negate<Predicate> not2 (const Predicate& pred)
{
    return binary_negate<Predicate>(pred);
}

It uses std::binary_negate in its implementation and binary_negate which is inherited from std::binary_function requires _Predicate::first_argument_type and _Predicate::second_argument_type in its templated arguments in the following way:

template <class _Predicate>
class binary_negate : public binary_function<typename _Predicate::first_argument_type,
                                             typename _Predicate::second_argument_type,
                                             bool>
{
    // ...
}

And my question is why I can write something like this if there are no typedefs for first_argument_type and second_argument_type in the Predicate that I am passing?

struct new_same
{
    bool operator()(int a, int b) const { return a == b; }
};
auto not_same = std::not2(std::function<bool(int, int)>(new_same()));
3 Answers

There is also a (from cppreference):

template< class Predicate >           (since C++11)
struct binary_negate;                 (deprecated in C++17)
                                      (removed in C++20)

Further, std::function does have the following typdefs:

first_argument_type    (deprecated in C++17)(removed in C++20)
second_argument_type   (deprecated in C++17)(removed in C++20)

why I can write something like this if there are no typedefs for first_argument_type and second_argument_type in the Predicate that I am passing?

The typedefs are there. binary_negate can get them from Predicate (which is a std::function in your case).

All this is deprecated in C++17 and removed in C++20. I have to admit, that I cannot tell you what the replacement is.

According to cppreference:

not2 is a helper function to create a function object that returns the complement of the binary predicate function passed. The function object created is of type std::binary_negate<Predicate>.

and:

The binary predicate type must define two member types, first_argument_type and second_argument_type, that are convertible to the predicate's parameter types. The function objects obtained from [...] std::function, or from another call to std::not2 have these types defined, as are function objects derived from the deprecated std::binary_function.

In my implementation (MinGW with GCC 9.2.0), std::function derives from _Maybe_unary_or_binary_function which, when instantiated with 2 arguments, derives from std::binary_function.


Note that this feature is deprecated. I cannot, unfortunately, find any replacements for it as of right now.

If you look at std::function implementation, you will see that it inherits a class named _Maybe_unary_or_binary_function. This inheritance cause the std::function to inherit std::binary_function if number of parameters is two.

  template<typename _Res, typename... _ArgTypes>
    class function<_Res(_ArgTypes...)>
    : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>,
      private _Function_base
    {
        ...
    }
  template<typename _Res, typename... _ArgTypes>
    struct _Maybe_unary_or_binary_function { };

  /// Derives from @c unary_function, as appropriate.
  template<typename _Res, typename _T1>
    struct _Maybe_unary_or_binary_function<_Res, _T1>
    : std::unary_function<_T1, _Res> { };

  /// Derives from @c binary_function, as appropriate.
  template<typename _Res, typename _T1, typename _T2>
    struct _Maybe_unary_or_binary_function<_Res, _T1, _T2>
    : std::binary_function<_T1, _T2, _Res> { };

by inheritance from std::binary_function, first_argument_type and second_argument_type are added to the std::function:

template<typename _Arg1, typename _Arg2, typename _Result>
 struct binary_function
    {
      /// @c first_argument_type is the type of the first argument
      typedef _Arg1     first_argument_type; 

      /// @c second_argument_type is the type of the second argument
      typedef _Arg2     second_argument_type;

      /// @c result_type is the return type
      typedef _Result   result_type;
    };
Related