如何使用 Boost.Hana 来确定仿函数是否具有可以使用特定模板参数调用的调用运算符?

How can I use Boost.Hana to determine whether a functor has a call operator that can be invoked with a particular template argument?

在我的应用程序中,我想在编译时确定任意仿函数类型 Func 是否具有可以使用给定显式模板参数 T 调用的无效调用运算符。 ,我想到了以下内容:

#include <boost/hana.hpp>
#include <iostream>
#include <type_traits>

namespace hana = boost::hana;

namespace detail 
{
    template <typename T>
    auto can_call = hana::is_valid([](auto &&f) -> 
        decltype(f.template operator()<T>()) { });
}

template <typename Func, typename T>
constexpr auto can_call() ->
    decltype(detail::can_call<typename std::remove_reference<T>::type>(
        std::declval<Func>())) { return {}; }

struct foo
{
    template <typename T, typename = 
        std::enable_if_t<!std::is_same<T, char>::value>>
    void operator()() const { }
};

int main()
{
    std::cout << "char: " << can_call<foo, char>() << std::endl;
    std::cout << "int: " << can_call<foo, int>() << std::endl;
}

我希望这个例子打印出来:

char: 0
int: 1

因为 char 模板参数类型在 foo 中明确 enable_if-ed 了。我试过以下编译器:

好像不太喜欢我用hana::is_valid()判断指定运算符是否存在。但是,我认为我使用它的方式与它的预期用途是一致的。

这是 gcc 中的错误,当代 clang 版本中更宽松的实现,还是我错误地实现了这种类型的检查?看起来这绝对是在 Hana 的驾驶室内;我只是想了解它的新模型 constexpr 元编程。

这里有一个变通方法,它使用结构 "functor" 而不是 lambda 和额外的间接层 is_valid 实例的类型来安抚 gcc。

namespace detail 
{
    template <typename T>
    struct check_can_call { 
      template <typename F>
      constexpr auto operator()(F&& f) -> 
        decltype(f.template operator()<T>()) { }
    };

    template <typename T>
    using is_call_valid = decltype(hana::is_valid(check_can_call<T>{}));

    template <typename T>
    constexpr is_call_valid<T> can_call{};
}