/ / Boost.Hana: Ako skontrolovať, či má funkcia špecializáciu pre určitý typ? - c ++, boost, c + + 14, sfinae, boost-hana

Boost.Hana: Ako skontrolovať, či má funkcia špecifikáciu pre určitý typ? - c ++, boost, c + + 14, sfinae, boost-hana

Mám funkciu šablóny, ktorá nemá predvolenú definíciu, ale špecializovala sa na nejaké typy:

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

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

Ako napíšem funkciu kontextu, ktorá mi povie, či typ T má špecializáciu na vyššie uvedenú funkciu?

Moje najlepšie úsilie:

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

Táto statická tvrdí požiare, ktoré by som očakával, že to nebude, keby som mal to správne.

odpovede:

6 pre odpoveď č. 1

Problém je v tom, že prechádzaš hana::types na funkciu, ktorá očakáva skutočné objekty. Keď píšete detail::has_foo(type_c<bar>, type_c<T>), Hana prejde hana::type_cs as-je detail::has_foo, Ale odvtedy foo nie je možné zavolať hana::types, zlyhá. Namiesto toho máte dve možnosti. Prvou možnosťou je pokračovať hana::types detail::has_foo, ale na použitie declval vnútri has_foo (všimnite si, že som pridal správne ref-kvalifikácie bar a 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>(), "");

Druhou možnosťou je zrušenie používania hana::type úplne a odovzdať skutočné predmety 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 {}; }

Tu používam std::declval robiť, ako keby som mal predmety správneho typu a potom zavolám detail::has_foo s týmito "objektmi". Ktorá z nich si vyberiete, je predovšetkým otázkou preferencie. Tiež v závislosti od vášho prípadu použitia možno skutočné objekty sú k dispozícii, keď voláte has_foo, Ak je to tak, môžete refactor na

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 uľahčí náš život odstránením zákazu lambdas v neustálom vyjadrení, čo vám umožní písať

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

čím sa odstráni potreba externého pomocníka.

Upozorňujeme tiež, že konkrétne nekontrolujete, či foošpecializácie pre T, ale naozaj, či foo(...) expresia je dobre formovaná. Toto môže byť v prípade preťaženia alebo ADL veľmi odlišné, malo by však byť dostatočné pre väčšinu prípadov použitia. Nie som si istý, či je možné presne skontrolovať, či je funkcia špecializovaná pre určitý typ.

Dúfam, že to pomôže!