2014-04-30 1 views
11

Мне нужно выяснить, имеет ли тип выдачи функцию X в качестве вызываемой функции с заданным списком параметров. Проверка должна не заботиться о возврате ценности однако.Как узнать, имеет ли тип функция-член с любым типом возврата?

Я нашел this solution от another Stack Overflow question который, кажется, хорошо работает. Что она делает это:

#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 {}; 

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

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

+0

так по существу вы хотите проверить, является ли функция будет 'возврат' 'недействительным 'или нет? – Valerij

ответ

10

Просто выражение 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; 
}; 

Live example.

+0

Проверка также возвращает true для изменяемых параметров. Любые решения для явных проверок? – stschindler

+0

@Tank Один из способов сделать это - принять '& T :: operator()' и применить к правильной сигнатуре в контексте SFINAE, но это означает, что вам также нужен тип возврата. Но это не то, чего хочет OP, AFAICT. – jrok

+0

правда, было просто интересно. благодаря – stschindler

1

Вы могли бы использовать:

#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'; 
}