Boost.Hana: 如何检查函数是否具有特定类型的特化?
Boost.Hana: How to check if function has specialisation for a certain type?
我有一个模板函数,默认情况下没有定义,但它由某些类型专门化:
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>());
然而,如果我做对了,我希望它不会触发这个静态断言。
这里的问题是您将 hana::type
s 传递给需要实际对象的函数。当您编写 detail::has_foo(type_c<bar>, type_c<T>)
时,Hana 将 hana::type_c
原样传递给 detail::has_foo
。但是由于 foo
不能用 hana::type
调用,所以它失败了。相反,您有两个选择。第一个选项是继续将 hana::type
s 传递给 detail::has_foo
,但在 declval
inside 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
来做,就像我有正确类型的对象一样,然后我用那些 "objects" 调用 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 将移除常量表达式中对 lambda 的禁令,让我们的生活变得更加轻松,这将允许您编写
constexpr auto has_foo = hana::is_valid([](bar& b, auto const& t) -> decltype(foo(b, t)) { });
因此不再需要外部助手。
另请注意,您并不是专门测试 foo
是否具有 T
的 specialization,而是真正测试 foo(...)
表达式是否是良构的。这在存在重载或 ADL 的情况下可能会略有不同,但对于大多数用例来说应该足够了。我不确定是否可以精确检查某个函数是否专用于某种类型。
希望对您有所帮助!
我有一个模板函数,默认情况下没有定义,但它由某些类型专门化:
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>());
然而,如果我做对了,我希望它不会触发这个静态断言。
这里的问题是您将 hana::type
s 传递给需要实际对象的函数。当您编写 detail::has_foo(type_c<bar>, type_c<T>)
时,Hana 将 hana::type_c
原样传递给 detail::has_foo
。但是由于 foo
不能用 hana::type
调用,所以它失败了。相反,您有两个选择。第一个选项是继续将 hana::type
s 传递给 detail::has_foo
,但在 declval
inside 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
来做,就像我有正确类型的对象一样,然后我用那些 "objects" 调用 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 将移除常量表达式中对 lambda 的禁令,让我们的生活变得更加轻松,这将允许您编写
constexpr auto has_foo = hana::is_valid([](bar& b, auto const& t) -> decltype(foo(b, t)) { });
因此不再需要外部助手。
另请注意,您并不是专门测试 foo
是否具有 T
的 specialization,而是真正测试 foo(...)
表达式是否是良构的。这在存在重载或 ADL 的情况下可能会略有不同,但对于大多数用例来说应该足够了。我不确定是否可以精确检查某个函数是否专用于某种类型。
希望对您有所帮助!