Boost.Hana: How to check if function has specialisation for a certain type?

情到浓时终转凉″ 提交于 2019-12-04 18:10:31

The problem here is that you're passing hana::types to a function that expects actual objects. When you write detail::has_foo(type_c<bar>, type_c<T>), Hana passes the hana::type_cs as-is to detail::has_foo. But since foo can't be called with hana::types, it fails. Instead, you have two options. The first option is to keep on passing hana::types to detail::has_foo, but to use declval inside has_foo (note that I have added the proper ref-qualifiers to bar and T):

#include <boost/hana.hpp>
#include <string>
namespace hana = boost::hana;


struct bar { };

template <typename T>
auto foo(bar&, T const&) -> void;

template <>
auto foo<std::string>(bar&, std::string const&) -> void { }

namespace detail {
    auto has_foo = hana::is_valid([](auto b, auto t) -> decltype(
        foo(hana::traits::declval(b), hana::traits::declval(t))
    ) { });
}

template <typename T>
constexpr auto has_foo() -> bool {
  return detail::has_foo(hana::type_c<bar&>, hana::type_c<T const&>);
}

static_assert(has_foo<std::string>(), "");

The other option is to drop the usage of hana::type altogether and to pass actual objects to detail::has_foo:

namespace detail {
    auto has_foo = hana::is_valid([](auto& b, auto const& t) -> decltype(foo(b, t)) { });
}

template <typename T>
constexpr auto has_foo() -> decltype(
    detail::has_foo(std::declval<bar&>(), std::declval<T const&>())
) { return {}; }

Here, I'm using std::declval to do as-if I had objects of the proper type, and then I call detail::has_foo with those "objects". Which one you pick is mainly a matter of preference. Also, depending on your use case, perhaps the actual objects are available when you call has_foo. If this is the case, you could refactor to

namespace detail {
    auto has_foo = hana::is_valid([](auto& b, auto const& t) -> decltype(foo(b, t)) { });
}

template <typename T>
constexpr auto has_foo(bar& b, T const& t) -> decltype(detail::has_foo(b, t)) { return {}; }

C++17 will make our life much easier by removing the ban on lambdas in constant expressions, which will allow you to write

constexpr auto has_foo = hana::is_valid([](bar& b, auto const& t) -> decltype(foo(b, t)) { });

thus removing the need for an external helper.

Also note that you're not specifically testing whether foo has a specialization for T, but really whether the foo(...) expression is well-formed. This can be subtly different in the presence of overloads or ADL, but it should be sufficient for most use cases. I'm not sure if it's possible to precisely check whether a function is specialized for some type.

Hope this helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!