Boost.Hana:如何检查函数是否具有特定类型的特化?

Sam*_*ett 1 c++ boost sfinae c++14 boost-hana

我有一个模板函数,默认情况下没有定义,但它由某些类型专门化:

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

template <>
auto foo<std::string>(bar &, const std::string &) -> void {}
Run Code Online (Sandbox Code Playgroud)

如何编写constexpr函数,告诉我类型T是否具有上述函数的特化?

我尽力而为:

namespace detail {

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

} // namespace detail

template <typename T>
constexpr auto has_foo() -> bool
{
  using hana::type_c;

  return detail::has_foo(type_c<bar>, type_c<T>);
}

static_assert(has_foo<std::string>());
Run Code Online (Sandbox Code Playgroud)

然而,这个静态断言会触发,如果我说得对,我希望它不会发生.

Lou*_*nne 6

这里的问题是你将hana::types 传递给一个需要实际对象的函数.当你写作时detail::has_foo(type_c<bar>, type_c<T>),Hana按hana::type_c原样传递detail::has_foo.但由于foo不能用hana::types 调用,它失败了.相反,你有两个选择.第一个选择是继续传递hana::types detail::has_foo,但要declval 在内部 使用has_foo(注意我已经添加了适当的ref-qualifiers到barT):

#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>(), "");
Run Code Online (Sandbox Code Playgroud)

另一种选择是完全放弃使用hana::type并将实际对象传递给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 {}; }
Run Code Online (Sandbox Code Playgroud)

在这里,我正在使用std::declval- 如果我有正确类型的对象,然后我调用detail::has_foo那些"对象".你选择哪一个主要是偏好问题.此外,根据您的使用情况,您可能在调用时可以使用实际对象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(bar& b, T const& t) -> decltype(detail::has_foo(b, t)) { return {}; }
Run Code Online (Sandbox Code Playgroud)

通过在常量表达式中删除lambdas禁令,C++ 17将使我们的生活更轻松,这将允许您编写

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

因此无需外部助手.

另外请注意,你并非专门测试是否foo专业化T,但真正能否foo(...)很好地形成表达.在存在重载或ADL时,这可能会略有不同,但对于大多数用例来说应该足够了.我不确定是否可以精确检查某个功能是否专用于某种类型.

希望这可以帮助!