如何为模板化运算符()编写尽可能最好的is_callable trait

Gor*_*vić 11 c++ sfinae c++11

我有像这样定义的is_callable trait:

#ifndef IS_CALLABLE_HPP
#define IS_CALLABLE_HPP

#include <type_traits>

namespace is_callable_detail
{
    struct no   {};
    struct yes  { no x[2]; };

    template<bool CallableArgs, typename Callable, typename ReturnType, typename ...Args>
    struct check_return
    {
        static const bool value = std::is_convertible<decltype(std::declval<Callable>()(std::declval<Args>()...)), ReturnType>::value;
    };

    template<typename Callable, typename ReturnType, typename ...Args>
    struct check_return<false, Callable, ReturnType, Args...>
    {
        static const bool value = false;
    };
}

template<typename Callable, typename Function>
struct is_callable;

template<typename Callable, typename ReturnType, typename ...Args>
struct is_callable<Callable, ReturnType(Args...)>
{
    private:
        template<typename T>
        static is_callable_detail::yes check(decltype(std::declval<T>()(std::declval<Args>()...)) *);
        template<typename T>
        static is_callable_detail::no  check(...);

        static const bool value_args = sizeof(check<Callable>(nullptr)) == sizeof(is_callable_detail::yes);
        static const bool value_return = is_callable_detail::check_return<value_args, Callable, ReturnType, Args...>::value;
    public:
        static const bool value = value_args && value_return;
};

#endif // IS_CALLABLE_HPP
Run Code Online (Sandbox Code Playgroud)

我的问题是如何检测没有参数且只返回类型为T的模板化operator()

template<typename T>
T operator()()
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)

要么

template<typename T, typename U>
auto operator()() -> decltype(std::declval<T>() + std::declval<U>())
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)

我知道这种情况很少见,但我想问有没有办法检测没有参数和一个或多个模板参数的模板化operator()的存在.

Luc*_*ton 4

如果你事先知道operator()不会过载,你可以尝试获取它的地址。如果operator()可能过载,则正结果将意味着存在,operator()而负结果将意味着不operator()存在,或者至少存在两个过载。

请注意,模板将(如预期)带来多个operator(). 但是,如果您确实知道非默认模板参数的数量,您可以尝试获取其地址operator()<T>(对于某些T希望不会触发 SFINAE 的类型)。

最后一点,我建议不要花太多时间尝试在不知道要传递哪些参数的情况下检查仿函数(或成员函数,出于同样的原因),就像您已经拥有的参数一样。C++11 使得编写和使用在表达式级别运行的通用代码变得非常容易。