После нескольких часов тренировок и некоторых серьезных обсуждений в чате C ++ , мы наконец-то получили версию, которая работает для функторов с возможно перегруженными или унаследованными operator()
и для указателей на функции, основанные на @ KerrekSB'sи версии @ BenVoigt.
#include <utility>
#include <type_traits>
template <typename F, typename... Args>
class Callable{
static int tester[1];
typedef char yes;
typedef yes (&no)[2];
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...));
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...));
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static yes test(int (&a)[sizeof(sfinae<G,Brgs...>(&G::operator()))]);
template <typename G, typename... Brgs>
static no test(...);
public:
static bool const value = sizeof(test<F, Args...>(tester)) == sizeof(yes);
};
template<class R, class... Args>
struct Helper{ R operator()(Args...); };
template<typename R, typename... FArgs, typename... Args>
class Callable<R(*)(FArgs...), Args...>
: public Callable<Helper<R, FArgs...>, Args...>{};
Живой пример на Ideone .Обратите внимание, что два провальных теста перегружены operator()
тестами.Это ошибка GCC с вариационными шаблонами, уже исправленная в GCC 4.7.Clang 3.1 также сообщает обо всех тестах как passed
.
Если вы хотите, чтобы operator()
с аргументами по умолчанию не удался, есть возможный способ сделать это, однако некоторые другие тесты начнут давать сбой в этот момент, и яон нашел слишком много хлопот, чтобы попытаться исправить это.
Редактировать: Как правильно заметил в комментарии @Johannes, у нас возникло небольшое несоответствие, а именно, что функторы, которыеопределение преобразования в указатель на функцию не будет определяться как «вызываемый».Это, имхо, довольно нетривиально исправить, поэтому я не буду беспокоиться об этом (пока).Если вам абсолютно нужна эта черта, оставьте комментарий, и я посмотрю, что я могу сделать.
Теперь, когда все это было сказано, ИМХО , идея для этой черты глупа.Почему у вас такие точные требования?Почему стандарт is_callable
не достаточно?
(Да, я думаю, что идея глупа. Да, я все еще пошел и построил это. Да, это было весело, очень много. Нет, яне безумие. По крайней мере это то, во что я верю ...)