2016-03-07 4 views
2

Учитывая (пониженная) осуществление detection idiomМожем ли мы использовать идентификатор обнаружения, чтобы проверить, имеет ли класс функцию-член с определенной сигнатурой?

namespace type_traits 
{ 
    template<typename... Ts> 
    using void_t = void; 

    namespace detail 
    { 
     template<typename, template<typename...> class, typename...> 
     struct is_detected : std::false_type {}; 

     template<template<class...> class Operation, typename... Arguments> 
     struct is_detected<void_t<Operation<Arguments...>>, Operation, Arguments...> : std::true_type {}; 
    } 

    template<template<class...> class Operation, typename... Arguments> 
    using is_detected = detail::is_detected<void_t<>, Operation, Arguments...>; 

    template<template<class...> class Operation, typename... Arguments> 
    constexpr bool is_detected_v = detail::is_detected<void_t<>, Operation, Arguments...>::value; 
} 

можно легко проверить, если класс foo содержит функцию-член bar

struct foo { 
    int const& bar(int&&) { return 0; } 
}; 

template<class T> 
using bar_t = decltype(std::declval<T>().bar(0)); 

int main() 
{ 
    static_assert(type_traits::is_detected_v<bar_t, foo>, "not detected"); 
    return 0; 
} 

Однако, как вы можете видеть, мы не можем определить, что foo::bar Тип аргумента - int&&. Обнаружение выполнено успешно, причина 0 может быть передана до foo::bar. Я знаю, что существует множество опций для проверки точной подписи функции (члена). Но я хотел бы знать, если можно изменить этот набор инструментов обнаружения, чтобы обнаружить, что аргумент типа foo::bar - это точно int&&.

[Я создал live demo этого примера.]

+0

Это просто, если единственной неизвестной частью является тип возврата. Вы также хотите охватить несколько аргументов, в которых вы хотите точно указать некоторые из них? Как насчет cv- и ref-квалификаторов функции-члена? – dyp

+2

Что-то вроде этого? http://coliru.stacked-crooked.com/a/38ffdc13080301c6 – dyp

+0

@ dyp В настоящее время 'is_detected_v ' будет определять, есть ли 'T' * любая * функция-член' bar', которая принимает 'int'. На первом этапе я хотел бы добавить какой-то 'is_detected_exact', который обнаруживает, что' T' имеет функцию-член 'bar', тип аргумента которого * точно *' int' или * точно * 'int &&' или * точно * 'int const &' и т. д. На втором этапе я хотел бы также проверить тип точного возврата, но я думаю, это легко, потому что 'bar_t' является именно возвращаемым типом (всякий раз, когда выражение внутри' decltype (...) 'хорошо сформирован). – 0xbadf00d

ответ

1

Адаптация идеи dypJarod42 и, я ve придумал

template<class T, typename... Arguments> 
using bar_t = std::conditional_t< 
    true, 
    decltype(std::declval<T>().bar(std::declval<Arguments>()...)), 
    std::integral_constant< 
     decltype(std::declval<T>().bar(std::declval<Arguments>()...)) (T::*)(Arguments...), 
     &T::bar 
    > 
>; 

Обратите внимание, что bar_t будет возвратным типом вызова bar. Таким образом, мы остаемся в соответствии с инструментарием. Мы можем обнаружить существование на

static_assert(type_traits::is_detected_v<bar_t, foo, int&&>, "not detected"); 

Однако, в то время как это решение делает именно то, что я намеревался, я ненавижу то, что мне нужно написать «столько сложный код» для каждого метода я хочу, чтобы обнаружить. Я попросил new question настроить эту проблему.

4

без изменения type_traits, вы можете сделать

template<typename T, T> struct helper {}; 

template<class T> 
using bar_t = decltype(helper<const int& (T::*)(int&&), &T::bar>{}); 

Demo

+3

Где «помощник» можно заменить на 'integ_constant'? – dyp

Смежные вопросы