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