Ниже приведено рабочее решение вашей проблемы, опубликованное на странице https://ideone.com/mxIVw3 — см. также живой пример.
Эта проблема в некотором смысле является продолжением вывести родительский класс унаследованного метода в C++. В моем ответе я определил черту типа member_class
, которая извлекает класс из заданного указателя на тип функции-члена. Ниже мы используем еще несколько признаков для анализа и последующего синтеза такого типа.
Во-первых, member_type
извлекает подпись, например. void (C::*)()
дает void()
:
template <typename M> struct member_type_t { };
template <typename M> using member_type = typename member_type_t <M>::type;
template <typename T, typename C>
struct member_type_t <T C::*> { using type = T;};
Затем member_class
извлекает класс, например. void (C::*)()
дает C
:
template<typename>
struct member_class_t;
template<typename M>
using member_class = typename member_class_t <M>::type;
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...)> { using type = C; };
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...) const> { using type = C const; };
// ...other qualifier specializations
Наконец, member_ptr
синтезирует указатель на тип функции-члена с учетом класса и подписи, например. C
+ void()
дать void (C::*)()
:
template <typename C, typename S>
struct member_ptr_t;
template <typename C, typename S>
using member_ptr = typename member_ptr_t <C, S>::type;
template <typename C, typename R, typename ...A>
struct member_ptr_t <C, R(A...)> { using type = R (C::*)(A...); };
template <typename C, typename R, typename ...A>
struct member_ptr_t <C const, R(A...)> { using type = R (C::*)(A...) const; };
// ...other qualifier specializations
Две предыдущие черты нуждаются в большей специализации, чтобы разные квалификаторы были более общими, например. const/volatile
или ref-квалификаторы. Есть 12 комбинаций (или 13, включая элементы данных); полная реализация находится здесь< /а>.
Идея состоит в том, что любые квалификаторы переносятся с помощью member_class
из типа указателя на функцию-член в сам класс. Затем member_ptr
переносит квалификаторы из класса обратно в тип указателя. Хотя квалификаторы находятся в типе класса, можно свободно манипулировать стандартными признаками, например. добавить или удалить const
, ссылки lvalue/rvalue и т. д.
А теперь вот ваш is_foo
тест:
template <typename T>
struct is_foo {
private:
template<
typename Z,
typename M = decltype(&Z::foo),
typename C = typename std::decay<member_class<M>>::type,
typename S = member_type<M>
>
using pattern = member_ptr<C const, void()>;
template<typename U, U> struct helper{};
template <typename Z> static auto test(Z z) -> decltype(
helper<pattern<Z>, &Z::foo>(),
// All other requirements follow..
std::true_type()
);
template <typename> static auto test(...) -> std::false_type;
public:
enum { value = std::is_same<decltype(test<T>(std::declval<T>())),std::true_type>::value };
};
Учитывая тип Z
, шаблон псевдонима pattern
получает правильный тип M
указателя-члена с decltype(&Z::foo)
, извлекает его decay
ed класс C
и сигнатуру S
и синтезирует новый тип указателя на функцию-член с классом C const
и сигнатурой void()
, т.е. void (C::*)() const
. Это именно то, что вам нужно: то же самое с вашим исходным жестко закодированным шаблоном, где тип Z
заменен правильным классом C
(возможно, базовым классом), найденным decltype
.
Графически:
M = void (Z::*)() const -> Z + void()
-> Z const + void()
-> void (Z::*)() const == M
-> SUCCESS
M = int (Z::*)() const& -> Z const& + int()
-> Z const + void()
-> void (Z::*)() const != M
-> FAILURE
На самом деле подпись S
здесь была не нужна, так что и member_type
тоже. Но я использовал его в процессе, поэтому я включаю его сюда для полноты картины. Это может быть полезно в более общих случаях.
Конечно, все это не будет работать при множественных перегрузках, потому что decltype
в данном случае не работает.
person
iavr
schedule
06.05.2014
decltype
уже упоминалось, могу я предложить вам написатьhelper<decltype(&B::foo), &B::foo> compiles;
? - person Ivan Vergiliev   schedule 06.05.2014<signature, decltype, pointer, convertable_magic>
? С магией в качестве параметра=void
(или чего-то подобного). - person Yakk - Adam Nevraumont   schedule 06.05.2014T
, то есть лучшие способы сделать это. - person Nawaz   schedule 06.05.2014X
методfoo()
, который можно вызывать с нулевыми аргументами и который возвращает что-то совместимое сR
? - person Yakk - Adam Nevraumont   schedule 06.05.2014