Функция для сравнения содержимого варианта не компилируется

В своих проектах я использую boost-variant исчерпывающе. Следовательно, для моих модульных тестов мне нужно проверить содержимое варианта на определенный T с определенным содержанием t,

Так что я разработал функцию cmpVariant для этой единственной цели и для удаления беспорядка из моих модульных тестов.

В некоторых случаях тип T не оснащен operator==чтобы пользователь мог передать функцию, удовлетворяющую EqualityCompare Требование (https://en.cppreference.com/w/cpp/named_req/EqualityComparable)

Теперь по какой-то непонятной причине следующий код не компилируется. Это говорит о том, что нет соответствующей функции?

Clang 6.0.1 Ошибка компилятора

prog.cc:22:5: error: no matching function for call to 'cmpVariant'
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
^~~~~~~~~~
prog.cc:6:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-1 &, const type-parameter-0-1 &)>' against '(lambda at prog.cc:19:24)'
bool cmpVariant(
^
1 error generated.

Кто-нибудь знает почему?

Код

#include <iostream>
#include <boost/variant.hpp>
#include <functional>

template<typename V, typename T>
bool cmpVariant(
const V& variant,
const T& t,
const std::function<bool(const T& u, const T& v)>& equiv = [](const T& u, const T& v) {return u == v; })
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}

int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto lambdaEquiv = [](const double& x, const double& y) { return x == y; };
std::function<bool(const double&, const double&)> equiv = lambdaEquiv;
cmpVariant(number, 3.2, equiv); // Works!
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
}

2

Решение

Компилятор не может сопоставить лямбду с типом параметра функции. Вы можете исправить это, явно создав экземпляр функции:

cmpVariant<boost::variant<double, int>, double>(number, 3.2, equiv);

Это явно немного многословно, так что есть еще одна возможность изменить объявление вашей функции на

template<typename V, typename T, typename Fct = std::function<bool(const T& u, const T& v)>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = [](const T& u, const T& v) {return u == v; })
{ /* Same as before. */ }

который можно назвать так

cmpVariant(number, 3.2, equiv); // Type deduction works now.

Улучшение, предложенное @DanielLangr в комментариях, заключается в использовании std::equal_to.

template<typename V, typename T, typename Fct = std::equal_to<T>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = std::equal_to<T>{})
{ /* Again, same as before. */ }

Одним из преимуществ здесь является избавление от std::function и его часто ненужные накладные расходы.

3

Другие решения

Принятие аргумента компаратора делает вывод проблематичным, поэтому вы можете захотеть изменить компаратор в параметр шаблона (возможно, избегая создания тяжелого std::function объект):

template<typename T> class t_EquilityComparator
{
public: bool operator ()(const T& u, const T& v) const { return u == v; }
};

template<typename V, typename T, typename Comparator = t_EquilityComparator<T>>
bool cmpVariant(
const V& variant,
const T& t,
const Comparator & equiv = Comparator{})
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}

int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto equiv = [](const double& x, const double& y) { return x == y; };
cmpVariant(number, 3.2, equiv); // This line fails to compile! Why?
}

онлайн компилятор

1

По вопросам рекламы [email protected]