/ / Boost.Hana: Comment vérifier si la fonction a une spécialisation pour un certain type? - c ++, boost, c ++ 14, sfinae, boost-hana

Boost.Hana: Comment vérifier si la fonction a une spécialisation pour un certain type? - c ++, boost, c ++ 14, sfinae, boost-hana

J'ai une fonction template qui n'a pas de définition par défaut mais qui est spécialisée par certains types:

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

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

Comment écrire une fonction constexpr qui me dit si le type T a une spécialisation pour la fonction ci-dessus?

Mon meilleur effort:

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

Ce statique affirme des incendies, cependant, ce à quoi je ne m'attendrais pas si j'avais bien compris.

Réponses:

6 pour la réponse № 1

Le problème ici est que vous "repassent hana::types à une fonction qui attend des objets réels. Quand tu écris detail::has_foo(type_c<bar>, type_c<T>), Hana passe la hana::type_cs comme est à detail::has_foo. Mais depuis foo peut être appelé avec hana::types, ça échoue. Au lieu de cela, vous avez deux options. La première option est de continuer à passer hana::types à detail::has_foomais à utiliser declval à l'intérieur has_foo (notez que j'ai ajouté les bons qualificatifs de ref à bar et 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>(), "");

L'autre option consiste à supprimer l'utilisation de hana::type tout à fait et pour passer des objets réels à 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 {}; }

Ici, je "m utilise std::declval faire comme si j'avais des objets du type approprié, puis j'appelle detail::has_foo avec ces "objets". Celui que vous choisissez est principalement une question de préférence. En outre, selon votre cas d’utilisation, les objets réels sont peut-être disponibles lorsque vous appelez. has_foo. Si tel est le cas, vous pouvez refactoriser à

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 nous facilitera la vie en supprimant l'interdiction des lambdas dans des expressions constantes, ce qui vous permettra d'écrire

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

éliminant ainsi le besoin d'une aide externe.

Notez également que vous ne testez pas spécifiquement si foo a un spécialisation pour T, mais vraiment si le foo(...) l'expression est bien formée. Cela peut être subtilement différent en présence de surcharges ou d'ADL, mais cela devrait suffire pour la plupart des cas d'utilisation. Je ne suis pas sûr qu'il soit possible de vérifier avec précision si une fonction est spécialisée pour un type quelconque.

J'espère que cela t'aides!