1

我有一个模板函数,默认情况下没有定义,但它专门用于某些类型:

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

然而,这个静态断言会触发,如果我做对了,我希望它不会触发。

4

1 回答 1

6

这里的问题是您将hana::types 传递给需要实际对象的函数。当您编写 时detail::has_foo(type_c<bar>, type_c<T>),Hana 将hana::type_cs 按原样传递给detail::has_foo. 但是由于foo不能用hana::types 调用,所以它失败了。相反,您有两个选择。第一个选项是继续将hana::types 传递给detail::has_foo,但在declval 内部 has_foo使用(请注意,我已将正确的引用限定符添加到barand 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 将取消对常量表达式中 lambda 的禁令,让我们的生活更轻松,这将允许您编写

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

从而消除了对外部助手的需要。

另请注意,您不是专门测试是否foo专门T,而是真正测试foo(...)表达式是否格式正确。在存在重载或 ADL 的情况下,这可能会略有不同,但对于大多数用例来说应该足够了。我不确定是否可以精确检查一个函数是否专门用于某种类型。

希望这可以帮助!

于 2016-02-15T21:45:57.110 回答