3
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

为什么大小为ht10?

4

3 回答 3

5

The problem here actually has nothing to do with Hana, it has to do with the way universal references are deduced. Just to clear up things, hana::type_c<T> == hana::type_c<U> is precisely equivalent to std::is_same<T, U>{}. There is no reference or cv-qualifier removing when comparing hana::types. You can look at various articles (like this or this) for these rules.

Now, let me go through your code and modify some things, with comments. First,

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

is redundant, because you're already creating a hana::tuple with hana::tuple_t. Hence, hana::tuple_t<T...> only is sufficient. Secondly, there's this line:

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

Instead of checking hana::find(...) != hana::nothing, I would instead use hana::contains, which expresses your intent better and might be more optimized too. In general, and especially with a metaprogramming library with Hana, don't try to reason as to what will be faster. Just state your intent as clearly as possible and hope for me to do my job properly on the implementation side :-). Hence, you'll end up with

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

Now, that hana::bool_c<...> really is redundant, because hana::contains already returns a boolean integral_constant. Hence, the above is equivalent to the simpler

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

Finally, putting all the bits together and simplifying, you get

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

I'm personally not a fan of taking the T&& as an argument, when all you want is actually the type of that object. Indeed, that forces you to actually provide an object to contains function, which might be unwieldy in some circumstances (what if you don't have an object around?). Furthermore, it can be confusing to be comparing values with types:

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

Instead, I would write the following if it was my own code:

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>)

But that is part of the interface of your function, and I guess you are a better judge than I to know what your needs are in terms of interface.

于 2015-11-26T00:53:34.507 回答
4

问题是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;
}
于 2015-11-25T22:49:11.260 回答
2

只是为了增加您的答案,您正在使用左值ht1调用。下面演示了传递右值和左值的情况:containstT&&

#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.
于 2015-11-25T23:29:35.963 回答