Как реализовать is_polymorphic_functor?

Я пытаюсь реализовать is_polymorphic_functor мета-функция для получения следующих результатов:

//non-polymorphic functor
template<typename T> struct X { void operator()(T); };

//polymorphic functor
struct Y { template<typename T> void operator()(T); };

std::cout << is_polymorphic_functor<X<int>>::value << std::endl; //false
std::cout << is_polymorphic_functor<Y>::value << std::endl; //true

Ну, это только пример. В идеале это должно работать для любой количество параметров, т.е. operator()(T...), Вот еще несколько тестов который я использовал для тестирования решения @Andrei Tita, которое не выполняется в двух тестах.

И я попробовал это:

template<typename F>
struct is_polymorphic_functor
{
private:
typedef struct { char x[1]; }  yes;
typedef struct { char x[10]; } no;

static yes check(...);

template<typename T >
static no check(T*, char (*) [sizeof(functor_traits<T>)] = 0 );
public:
static const bool value = sizeof(check(static_cast<F*>(0))) == sizeof(yes);
};

который пытается использовать следующую реализацию functor_traits:

//functor traits
template <typename T>
struct functor_traits : functor_traits<decltype(&T::operator())>{};

template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...) const> : functor_traits<R(C::*)(A...)>{};

template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...)>
{
static const size_t arity = sizeof...(A) };

typedef R result_type;

template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
};
};

что дает следующую ошибку для полиморфных функторов:

error: decltype cannot resolve address of overloaded function

Как исправить эту проблему и сделать is_polymorphic_functor работать как положено?

2

Решение

Это работает для меня:

template<typename T>
struct is_polymorphic_functor
{
private:
//test if type U has operator()(V)
template<typename U, typename V>
static auto ftest(U *u, V* v) -> decltype((*u)(*v), char(0));
static std::array<char, 2> ftest(...);

struct private_type { };

public:
static const bool value = sizeof(ftest((T*)nullptr, (private_type*)nullptr)) == 1;
};
5

Другие решения

Учитывая, что неполиморфные функторы не имеют перегруженных operator():

template<typename T>
class is_polymorphic_functor {
template <typename F, typename = decltype(&F::operator())>
static constexpr bool get(int) { return false; }
template <typename>
static constexpr bool get(...) { return true; }

public:
static constexpr bool value = get<T>(0);
};
2

template<template<typename>class arbitrary>
struct pathological {
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};

Вышеуказанный функтор является неполиморфным, если существует ровно один T такой, что arbitrary<T>::value правда.

Это не сложно создать template<T> функтор, который верно на int и, возможно, doubleи верно только на double if (произвольное вычисление возвращает 1).

Так что бескомпромиссный is_polymorphic выходит за рамки этой вселенной.

Если вам не нравится выше (потому что это явно занимает больше, чем просто intдругие типы просто не могут найти перегрузку), мы могли бы сделать это:

template<template<typename>class arbitrary>
struct pathological2 {
void operator()(int) const {}
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};

где проверяется вторая «перегрузка», и если нет T, для которого она принята, то первая перегрузка возникает для каждого отдельного типа.

2
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector