оператор == в качестве значения по умолчанию для std :: function

0

Рассмотрим следующую функцию, которая сравнивает два vector T и проверяет, что они одинаковы с использованием функции T.operator==.

template<typename T>
bool Verify(const std::vector<T>& a, const std::vector<T>& b)
{
    if (a.size() != b.size())
        return false;

    for (int ii=0; ii<a.size(); ii++)
        if (!(a[ii] == b[ii]))
            return false;

    return true;
}

Проблема состоит в том, что T не может содержать operator== поэтому я хочу обновить функцию Verify чтобы она принимала функцию сравнения в качестве аргумента. Таким образом, пользователь может вызвать функцию, предоставляющую пользовательскую функцию сравнения.

Что-то вроде:

template<typename T>
bool Verify(const std::vector<T>& a, const std::vector<T>& b, std:function<bool(T,T)> isEqual)

Проблема в следующем: могу ли я установить значение по умолчанию isEqual как T.operator==?

Если да, как?
Если нет, каковы мои альтернативы.

  • 0
    Вы пытались скомпилировать его вместо того, чтобы спрашивать нас?
  • 1
    Компараторы, как и любые другие функции в универсальных алгоритмах, обычно берут просто по значению, а не в std::function . template<class T, class F> bool Verify(vector<T> const& a, vector<T> const& b, F);
Теги:
function
function-pointers

5 ответов

4
Лучший ответ

Вы можете установить стандартный std::equal_to() сравнения std::equal_to() качестве значения по умолчанию:

template<typename T>
bool Verify( const std::vector<T>& a, 
             const std::vector<T>& b, 
             std::function<bool(const T&,const T&)> isEqual = std::equal_to<T>()
           );
  • 0
    Разве не equal_to<> C ++ 1y? (ссылаясь на редактирование dribeas)
  • 0
    @ DyP, насколько я знаю, он был добавлен начиная с C ++ 11, однако легко написать собственный эквивалент.
Показать ещё 2 комментария
2

Общий подход, применяемый STL и другими, заключается в том, чтобы передать функтор сравнения в качестве дополнительного параметра шаблона, который по умолчанию, но может быть переопределен. Вот пример:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

template <class T, class Compare = std::equal_to<T>>
bool equal(
   const std::vector<T>& lhs,
   const std::vector<T>& rhs,
   Compare comp = {})  // take comparison operator, default where appropriate
{
    if(lhs.size() != rhs.size())
       return false;

    for(size_t x = 0, e = lhs.size(); x < e; ++x)
    {
        if(!comp(lhs[x], rhs[x]))
           return false;
    }

    return true;
}

bool false_equality(int x, int y)
{
    return false;
}

int main()
{
    std::vector<int> a{1, 2, 3, 4};
    std::vector<int> b{1, 2, 3, 4};

    cout << equal(a, b) << " but " << equal(a, b, false_equality) << "\n";
    return 0;
}
  • 0
    Compare comp = {} немного проще;)
  • 0
    Это! Я все еще привыкаю к включению унифицированной инициализации в мой код. Спасибо, отредактировал.
Показать ещё 2 комментария
1

Правильный ответ был задан Manu343726, используйте std::equal_to<>. То, что не очевидно в этом ответе, - это то, почему вы не хотите напрямую привязывать оператора.

В C++ перегруженные операторы (в большинстве случаев) могут быть реализованы как как функция-член первого аргумента, так и как свободная функция. Язык предназначен для того, чтобы иметь возможность разрешить a == b путем определения того, каким образом задан данный оператор, или, возможно, ни один из способов (для фундаментального типа). С другой стороны, когда вы пытаетесь получить адрес оператора вручную, вам нужно знать, как определяется оператор (если он действительно определен).

С подходом установки значения по умолчанию isEqual является T.operator == (правильным синтаксисом будет: &T::operator==), вы сможете использовать аргумент по умолчанию только для тех типов, для которых определен operator== как функция-член, но он будет терпеть неудачу для типов, где он определен как свободная функция.

То же самое происходит, если вы пытаетесь использовать версию бесплатной функции, за исключением того, что в этом случае это еще хуже, поскольку вы даже не знаете, какое пространство имен было определено оператором (вы не можете программно извлечь пространство имен типа). Аргумент зависимого поиска не применяется для определения адреса функции

Операторы являются специальными в этом языке, и существуют специальные правила, предназначенные для облегчения определения (функция free/function) и использования (ADL) оператора в коде, но эти правила не применяются к принятию адреса оператора. Если вам нужно связать оператор, простым ответом является создание вспомогательного типа, который вызывает оператор, а затем связывает его.

1

Объект std::function действительно можно сравнить только с nullptr, а также можно построить с помощью nullptr.

Это означает, что вы можете сделать значение аргумента по умолчанию nullptr и сравнить с ним, чтобы увидеть, следует ли использовать функцию равенства объектов.

0

Вы можете использовать функцию перегрузки и иметь обе функции. В качестве последнего аргумента можно было бы использовать функцию, в то время как у другого будет меньше аргументов. Сделать функцию с одним аргументом меньше вызова другого передающего оператора == в качестве последнего аргумента.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню