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?
Проблема здесь на самом деле не имеет ничего общего с Ханой, она связана с тем, как выводятся универсальные ссылки. Просто чтобы прояснить ситуацию, hana::type_c<T> == hana::type_c<U>
точно эквивалентно std::is_same<T, U>{}
, При сравнении нет ссылки или cv-квалификатора hana::type
s. Вы можете посмотреть различные статьи (например, этот или же этот) по этим правилам.
Теперь позвольте мне пройтись по вашему коду и изменить некоторые вещи, с комментариями. Первый,
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>)
Но это часть интерфейса вашей функции, и я думаю, вы лучше, чем я, знаете, каковы ваши потребности с точки зрения интерфейса.
Проблема заключается в 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;
}
Просто чтобы добавить к вашему ответу, ваш 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.