Фильтрация кортежа в boost hana

template<class... Ts, class T>
constexpr auto contains(T&&){
auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);
return hana::bool_c<hana::find(types, hana::type_c<T>) != hana::nothing>;
}

auto ht = hana::make_tuple(1,2,3,'c');

auto ht1 = hana::filter(ht, [](auto t){
return contains<int,float,double>(t);
});
//prints 0
std::cout << hana::size(ht1) << std::endl;

Я не уверен, правильно ли я использую Boost Hana, но contains похоже на работу.

std::cout << contains<int,float,double>(5) << std::endl;   // 1
std::cout << contains<int,float,double>('c') << std::endl; // 0
std::cout << contains<int,float,double>(5.0f) << std::endl; // 1

Почему размер ht1 0?

3

Решение

Проблема здесь на самом деле не имеет ничего общего с Ханой, она связана с тем, как выводятся универсальные ссылки. Просто чтобы прояснить ситуацию, hana::type_c<T> == hana::type_c<U> точно эквивалентно std::is_same<T, U>{}, При сравнении нет ссылки или cv-квалификатора hana::types. Вы можете посмотреть различные статьи (например, этот или же этот) по этим правилам.

Теперь позвольте мне пройтись по вашему коду и изменить некоторые вещи, с комментариями. Первый,

  auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);

избыточно, потому что вы уже создаете hana::tuple с hana::tuple_t, Следовательно, hana::tuple_t<T...> только достаточно. Во-вторых, есть эта строка:

  return hana::bool_c<hana::find(types, hana::type_c<T>) != hana::nothing>;

Вместо проверки hana::find(...) != hana::nothingЯ бы вместо этого использовал hana::contains, который лучше выражает ваши намерения и может быть более оптимизированным. В общем и особенно с библиотекой метапрограммирования с Hana, не пытайтесь рассуждать о том, что будет быстрее. Просто заявите о своих намерениях как можно более четко и надеемся, что я выполню свою работу должным образом на стороне реализации 🙂 Следовательно, вы в конечном итоге

return hana::bool_c<hana::contains(types, hana::type_c<T>)>;

Теперь, когда hana::bool_c<...> действительно избыточно, потому что hana::contains уже возвращает логическое значение integral_constant, Следовательно, вышеупомянутое эквивалентно более простому

return hana::contains(types, hana::type_c<T>);

Наконец, собрав все воедино и упростив, вы получите

template<class... Ts, class T>
constexpr auto contains(T&&){
return hana::contains(hana::tuple_t<Ts...>, hana::type_c<T>);
}

Я лично не фанат принятия T&& в качестве аргумента, когда все, что вы хотите, это на самом деле тип этого объекта. Действительно, это заставляет вас на самом деле обеспечить объект в contains функция, которая может быть громоздкой в ​​некоторых обстоятельствах (что, если у вас нет объекта вокруг?). Кроме того, может быть непонятно сравнение значений с типами:

contains<int, char, double>(3.5) // wtf, 3.5 is not in [int, char, double]!

Вместо этого я написал бы следующее, если бы это был мой собственный код:

template<class... Ts, class T>
constexpr auto contains(T type){
return hana::contains(hana::tuple_t<Ts...>, type);
}

// and then use it like
contains<int, char, double>(hana::type_c<double>)

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

5

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

Проблема заключается в T&&Я думаю, это выводит тип, чтобы иметь тип T& Который означает, что hana::type_c<T> != hana::type_c<T&> Исправление состоит в том, чтобы оставить && потому что они не нужны.

template<class... Ts, class T>
constexpr auto contains(T){
auto types = hana::tuple_t<Ts...>;
return hana::find(types, hana::type_c<T>) != hana::nothing;
}
4

Просто чтобы добавить к вашему ответу, ваш ht1 звонил contains с t lvalue. Следующее демонстрирует T&& в случае передачи rvalue и lvalue:

#include<boost/hana.hpp>

namespace hana = boost::hana;

template<class T>
void test1(T&&) {
static_assert(hana::type_c<T> == hana::type_c<int>, "");
}

int main() {
static_assert(hana::type_c<int> != hana::type_c<int&&>, "");
test1(5);
int x = 5;
test1(x); //fails
}

лязг на выходе:

main.cpp:7:3: error: static_assert failed ""static_assert(hana::type_c<T> == hana::type_c<int>, "");
^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:3: note: in instantiation of function template specialization 'test1<int &>' requested here
test1(x); //fails
^
1 error generated.
2