2013-06-19 8 views
11

Jest (pozornie) ładny C++ 03 sposób dowiedzieć się, czy rodzaj posiada funkcję składową lub operatora:C++ 11 sposobów na stwierdzenie, czy dany typ ma funkcję członka, czy obsługuje operatora?

https://github.com/jaredhoberock/is_call_possible/blob/master/is_call_possible.hpp

ma tam nowoczesny C++ 11 sposobów, aby to zrobić? Lepiej nie włączać zewnętrznego kodu i używać tylko standardu.

+0

Czy jest jakiś cel pytania lub jesteś po prostu ciekawy – aaronman

Odpowiedz

2

Nie, to prawie tak samo. Mniej więcej. Implementacje są różne, ale można zastąpić niektóre metafunkcje używane wewnętrznie przez tę implementację standardowymi cechami biblioteki. Ale nie ma sposobu na wykrycie, czy można wywołać funkcję w pewnym typie, biorąc pod uwagę pewien zestaw argumentów.

To za concepts (PDF).

19

ten działa ze wszystkimi przypadków testowych podanych w github (Demo: http://ideone.com/ZLGp4R):

#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>()...) 
      //    ^^^^^^^^^^ replace this with the member you need. 
     ), R>::value 
    >::type 
> : public std::true_type {}; 
16

C++ 11 dodaje się nowy trik, który często żartobliwie nazywają "CFINAE" (awaria kompilacja nie jest błąd) .

Korzysta z operatora decltype i regularnych właściwości SFINAE.

Rozważmy następującą funkcję:

template <typename X, typename Y> 
static auto check(X& x, Y& y) -> decltype(x >> y); 

Należy wziąć pod uwagę podczas przeciążenia tylko wtedy X i Y są typu do których operator zmiana jest zdefiniowana. Dodaj zwykłe przeciążenie - wszystkie przeciążenia dla check i masz mechanizm do sprawdzenia, czy można skompilować dowolne wyrażenie.

I rzeczywiście, jest to zasada opracowana w eksperymentalnej bibliotece Origin autorstwa Andrew Suttona (jednego z autorów propozycji Concepts Lite). W rzeczywistości mój przykład jest pobierany bezpośrednio z here w celu implementacji koncepcji Streamable.

polecam następującą prezentację z GoingNative 2012 przez Andrew Sutton i Bjarne Stroustrup gdzie dają wstęp do nowe spojrzenie na koncepcje i bibliotekę Pochodzenie:

http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/A-Concept-Design-for-C-

1

używam następujący znanego podejścia na podstawie SFINAE:

#define TYPE_SUPPORTS(ClassName, Expr)       \ 
    template<typename U>           \ 
    struct ClassName            \ 
    {               \ 
    private:              \ 
    template<typename>           \ 
    static constexpr std::false_type test(...);    \ 
                   \ 
    template<typename T = U>         \ 
    static decltype((Expr), std::true_type{}) test(int) ;  \ 
                   \ 
    public:              \ 
    static constexpr bool value = decltype(test<U>(0))::value; \ 
    }; 

Głównym celem makra jest uproszczenie dodawania kontroli typów. Makro definiuje klasę, która umożliwia wykonanie dowolnego sprawdzenia dla typu T.

Jako przykład, aby sprawdzić, czy std::begin() można nazwać dla typu:

namespace detail 
{ 
    TYPE_SUPPORTS(SupportsBegin, std::begin(std::declval<T>())) 
} 

template<typename T> 
bool supportsBegin() 
{ 
    return detail::SupportsBegin<T>::value; 
} 

Oczywiście, detail nazw i funkcja otoki są cały cukier syntaktyczny, ale poprawić składnię nieco na boku dzwoniącego .

Powiązane problemy