Рассмотрим следующую функцию, которая сравнивает два 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==
?
Если да, как?
Если нет, каковы мои альтернативы.
Вы можете установить стандартный 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>()
);
equal_to<>
C ++ 1y? (ссылаясь на редактирование dribeas)
Общий подход, применяемый 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;
}
Compare comp = {}
немного проще;)
Правильный ответ был задан Manu343726, используйте std::equal_to<>
. То, что не очевидно в этом ответе, - это то, почему вы не хотите напрямую привязывать оператора.
В C++ перегруженные операторы (в большинстве случаев) могут быть реализованы как как функция-член первого аргумента, так и как свободная функция. Язык предназначен для того, чтобы иметь возможность разрешить a == b
путем определения того, каким образом задан данный оператор, или, возможно, ни один из способов (для фундаментального типа). С другой стороны, когда вы пытаетесь получить адрес оператора вручную, вам нужно знать, как определяется оператор (если он действительно определен).
С подходом установки значения по умолчанию isEqual является T.operator == (правильным синтаксисом будет: &T::operator==
), вы сможете использовать аргумент по умолчанию только для тех типов, для которых определен operator==
как функция-член, но он будет терпеть неудачу для типов, где он определен как свободная функция.
То же самое происходит, если вы пытаетесь использовать версию бесплатной функции, за исключением того, что в этом случае это еще хуже, поскольку вы даже не знаете, какое пространство имен было определено оператором (вы не можете программно извлечь пространство имен типа). Аргумент зависимого поиска не применяется для определения адреса функции
Операторы являются специальными в этом языке, и существуют специальные правила, предназначенные для облегчения определения (функция free/function) и использования (ADL) оператора в коде, но эти правила не применяются к принятию адреса оператора. Если вам нужно связать оператор, простым ответом является создание вспомогательного типа, который вызывает оператор, а затем связывает его.
Объект std::function
действительно можно сравнить только с nullptr
, а также можно построить с помощью nullptr
.
Это означает, что вы можете сделать значение аргумента по умолчанию nullptr
и сравнить с ним, чтобы увидеть, следует ли использовать функцию равенства объектов.
Вы можете использовать функцию перегрузки и иметь обе функции. В качестве последнего аргумента можно было бы использовать функцию, в то время как у другого будет меньше аргументов. Сделать функцию с одним аргументом меньше вызова другого передающего оператора == в качестве последнего аргумента.
std::function
.template<class T, class F> bool Verify(vector<T> const& a, vector<T> const& b, F);