Boost.Hana: Как проверить, имеет ли функция специализацию для определенного типа?

У меня есть функция шаблона, которая по умолчанию не имеет определения, но специализируется на некоторых типах:

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

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

Как мне написать функцию 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>());

Однако этот статический огонь возжигает, чего я бы не ожидал, если бы понял это правильно.

1

Решение

Проблема в том, что вы проходите мимо hana::typeс функцией, которая ожидает реальных объектов. Когда ты пишешь detail::has_foo(type_c<bar>, type_c<T>)Хана проходит hana::type_cс как есть detail::has_foo, Но с тех пор foo не может быть вызван с hana::typeс, это не удается. Вместо этого у вас есть два варианта. Первый вариант — продолжать проходить hana::typeс detail::has_foo, но использовать declval внутри has_foo (обратите внимание, что я добавил соответствующие ref-квалификаторы в bar а также 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>(), "");

Другой вариант — отказаться от использования 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 {}; }

Здесь я использую 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 {}; }

C ++ 17 сделает нашу жизнь намного проще, сняв запрет на лямбды в константных выражениях, что позволит вам писать

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

таким образом устраняя необходимость во внешнем помощнике.

Также обратите внимание, что вы не тестируете foo имеет специализация за Tно действительно ли foo(...) выражение хорошо сформировано. Это может незначительно отличаться при наличии перегрузок или ADL, но этого должно быть достаточно для большинства случаев использования. Я не уверен, что можно точно проверить, является ли функция специализированной для какого-либо типа.

Надеюсь это поможет!

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]