Как узнать, есть ли у типа функция-член с любым возвращаемым типом?

Мне нужно выяснить, есть ли у заданного типа функция X как вызываемая функция с заданным списком параметров. Однако проверка не должна заботиться о возвращаемом значении.

Я нашел это решение из еще один вопрос о переполнении стека, который, кажется, работает хорошо. Что он делает, так это:

#include <type_traits>

template <typename C, typename F, typename = void>
struct is_call_possible : public std::false_type {};

template <typename C, typename R, typename... A>
struct is_call_possible<C, R(A...),
    typename std::enable_if<
        std::is_same<R, void>::value ||
        std::is_convertible<decltype(
            std::declval<C>().operator()(std::declval<A>()...)
        ), R>::value
    >::type
> : public std::true_type {};

Это именно то, что я хочу, за исключением того, что в чеке вы также указываете желаемый тип возврата. Я пытался найти способ изменить это, чтобы иметь возможность проверять, не принимая во внимание тип возвращаемого значения, но я не мог найти способ.

Кто-нибудь знает как это сделать?


person Tobias    schedule 30.04.2014    source источник
comment
так что, по сути, вы хотите проверить, вернет ли функция void или нет?   -  person Valerij    schedule 30.04.2014


Ответы (2)


Просто выполните выражение SFINAE и отбросьте результат:

template <typename C, typename... Args>
struct is_call_possible {
private:
    template<typename T>
    static auto check(int)
        -> decltype( std::declval<T>().operator()(std::declval<Args>()...),
                     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                     // overload is removed if this expression is ill-formed
           std::true_type() );

    template<typename>
    static std::false_type check(...);
public:
    static constexpr bool value = decltype(check<C>(0))::value;
};

Живой пример.

person jrok    schedule 30.04.2014
comment
Проверка также возвращает true для конвертируемых параметров. Любые решения для явных проверок? - person stschindler; 30.04.2014
comment
@Tank Один из способов сделать это - взять &T::operator() и привести к правильной подписи в контексте SFINAE, но это означает, что вам также нужен возвращаемый тип. Но это не то, чего хочет ОП, AFAICT. - person jrok; 30.04.2014

Вы можете использовать:

#include <iostream>

namespace Detail {
    struct is_callable
    {
        template<typename F, typename... A>
        static decltype(std::declval<F>()(std::declval<A>()...), std::true_type())
        test(int);

        template<typename F, typename... A>
        static std::false_type
        test(...);
    };
} // namespace Detai

template<typename F, typename... A>
using is_callable = decltype(Detail::is_callable::test<F, A...>(0));

struct X {
    int operator ()(int) { return 0; }
};

int main() {
    std::cout << is_callable<X>() << '\n';
    std::cout << is_callable<X, int>() << '\n';
}
person Community    schedule 30.04.2014