在boost hana中过滤元组
Filtering a tuple in 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?
问题是 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
是一个左值。下面演示T&&
在传递一个右值和一个左值的情况下:
#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
}
clang 输出:
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.
这里的问题其实与Hana无关,与通用引用的推导方式有关。澄清一下,hana::type_c<T> == hana::type_c<U>
正好等同于 std::is_same<T, U>{}
。比较 hana::type
时没有引用或 cv 限定符删除。您可以查看各种文章(例如 this or this)了解这些规则。
现在,让我检查一下您的代码并修改一些内容,并附上评论。首先,
auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);
是多余的,因为您已经用 hana::tuple_t
创建了 hana::tuple
。因此,仅 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
已经 returns 一个布尔值 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&&
作为参数,因为您实际上只需要该对象的类型。实际上,这迫使您实际提供 object 到 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>)
但那是你的函数接口的一部分,我想你比我更清楚你在接口方面的需求。
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?
问题是 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
是一个左值。下面演示T&&
在传递一个右值和一个左值的情况下:
#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
}
clang 输出:
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.
这里的问题其实与Hana无关,与通用引用的推导方式有关。澄清一下,hana::type_c<T> == hana::type_c<U>
正好等同于 std::is_same<T, U>{}
。比较 hana::type
时没有引用或 cv 限定符删除。您可以查看各种文章(例如 this or this)了解这些规则。
现在,让我检查一下您的代码并修改一些内容,并附上评论。首先,
auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);
是多余的,因为您已经用 hana::tuple_t
创建了 hana::tuple
。因此,仅 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
已经 returns 一个布尔值 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&&
作为参数,因为您实际上只需要该对象的类型。实际上,这迫使您实际提供 object 到 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>)
但那是你的函数接口的一部分,我想你比我更清楚你在接口方面的需求。