замена std::binary_function

std::binary_function теперь устарела и будет удалена в c++17. Я искал в разных публикациях, но не смог найти точного способа заменить его. Я хотел бы знать, как написать следующий код в c++11.

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);
    }
};

РЕДАКТИРОВАТЬ

Я использую функции следующим образом:

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

input и output - это std::vector внутри цикла for.


person Luis    schedule 14.10.2015    source источник
comment
зачем вам это нужно? Черты типа и decltype могут определить тип operator() без необходимости binary_function   -  person Bryan Chen    schedule 14.10.2015
comment
Как вы используете эти функции шаблона? Ответ зависит от использования.   -  person Rostislav    schedule 14.10.2015
comment
stackoverflow.com/a/22863957/642626 так вы узнаете аргументы и возвращаемый тип любого вызываемого объекта.   -  person Bryan Chen    schedule 14.10.2015
comment
Стандартная библиотека LLVM C++ все еще использует binary_function в конце 2020 г. github. com/llvm/llvm-project/blob/main/libcxx/include/ Более того, clang++ --std=c++17 по-прежнему можно компилировать код, который использует binary_function github.com/llvm/llvm-project/blob/main/libcxx/include/   -  person x4444    schedule 29.12.2020


Ответы (4)


Во-первых, я советую посмотреть CppCon 2015: Stephan T. Lavavej "Функциональность: что нового и правильное использование". . std::binary_function упоминается на слайде 36 примерно на 36-й минуте видео. Вы можете найти слайды на github.com/CppCon/CppCon2015). В нем не рассказывается, почему вам не следует использовать std::binary_function, но если вы используете что-то, что устарело с C++11, то вам, вероятно, будет полезно это посмотреть.

Если вам нужно фактическое обоснование того, что вы не используете его, попробуйте n4190:

unary_function/binary_function были полезными помощниками, когда адаптерам эры C++98 требовался arguments_type/etc. определения типов. Такие определения типов не нужны, учитывая идеальную переадресацию C++11, decltype и т.д. (И они неприменимы к перегруженным/шаблонным операторам вызова функций.) Даже если класс хочет предоставить эти определения типов для обратной совместимости, он может сделать это напрямую (с небольшими потерями в многословии) вместо того, чтобы наследовать от unary_function/binary_function, которые это то, что сам Стандарт начал делать, когда эти помощники устарели.

Теперь он вам просто не нужен, поэтому вы можете удалить все его следы из своей программы.

В C++14 были добавлены прозрачные компараторы. Но это можно реализовать на C++11. Просто настройте его для 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));
    }
}
};

Теперь можно вывести тип:

std::max_element(v.begin(), v.end(), absoluteLess<>());
person user5443145    schedule 14.10.2015

Единственное, что делает std::binary_function, — это предоставляет определения типов членов result_type, first_argument_type и second_argument_type. И единственная вещь в стандартной библиотеке, которая использует эти определения типов, это std::not2, что 1) строго заменено C++17 std::not_fn, 2) в любом случае легко заменяется лямбда-выражением и 3) устарело в C++17 и, вероятно, будет удалено в следующей версии.

Если по какой-либо причине вам нужно использовать not2, устаревшие связыватели (bind1st/bind2nd, оба объявлены устаревшими в C++11 и удалены в C++17) или какую-то древнюю стороннюю вещь, следующую этому протоколу, замена чтобы определить typedefs непосредственно в вашем классе:

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

В противном случае просто удалите наследство.

person T.C.    schedule 14.10.2015

Я полагаю, вы ищете std::function.

person ulatekh    schedule 17.02.2020
comment
Было бы неплохо, если бы вы показали, как это реализовать в коде из вопроса. - person Dharman; 17.02.2020
comment
@Dharman: Это казалось излишним... std::function инкапсулирует все, что ведет себя как функция, с любым количеством параметров. - person ulatekh; 24.02.2020

binary_function можно легко заменить функциями lambda:

#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;
}

Протестируйте в Интернете

person Adrian Maire    schedule 03.09.2020