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ď č. 1Problém je v tom, že prechádzaš hana::type
s 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_c
s as-je detail::has_foo
, Ale odvtedy foo
nie je možné zavolať hana::type
s, zlyhá. Namiesto toho máte dve možnosti. Prvou možnosťou je pokračovať hana::type
s 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
má š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!