2013-09-02 14 views
8

w C++ 11, aby dowiedzieć się, czy dana klasa posiada funkcję składową size, można zdefiniować następujące testy pomocnika:Korzystanie SFINAE wykryć członkiem funkcję

template <typename T> 
struct has_size_fn 
{ 
    typedef char (& yes)[1]; 
    typedef char (& no)[2]; 

    template <typename C> static yes check(decltype(&C::size)); 
    template <typename> static no check(...); 

    static bool const value = sizeof(check<T>(0)) == sizeof(yes); 
}; 

Czy istnieje podobny trick robi to w C++ 98 bez polegania na rozszerzeniach kompilatorów, takich jak typeof?

+0

To również wykryje członków danych. – jrok

+1

Może to być przydatne: http://pl.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector - _Edit: _ also: http://stackoverflow.com/questions/257288/is-it-possible- to-write-ac-template-to-check-for-a-functions-exist (nie przestawaj przy pierwszej odpowiedzi) –

+0

@jrok W porządku, będzie używane w funkcji szablonu, która spowoduje kompilację błąd, jeśli nie jest funkcją - mogę z tym żyć. – nijansen

Odpowiedz

8

Właściwie Twój wykrywania potencjalnie błędne.

Problemem jest to, że wszystko, co wykryły, że C ma człon size:

  • może to być atrybut
  • może to być metoda z cokolwiek podpis
  • nie może być nawet kilka metody (z różnymi sygnaturami)

Jeśli chcesz wzmocnić wykrywanie, powinieneś spróbować wykryć tylko prawosize (niezależnie od tego, jakie jest prawo). Here is such a hardened detection.

template <typename T> 
class has_size { 
private: 
    typedef char Yes; 
    typedef Yes No[2]; 

    template <typename U, U> struct really_has; 

    template <typename C> static Yes& Test(really_has <size_t (C::*)() const, 
             &C::size>*); 

    // EDIT: and you can detect one of several overloads... by overloading :) 
    template <typename C> static Yes& Test(really_has <size_t (C::*)(), 
             &C::size>*); 

    template <typename> static No& Test(...); 

public: 
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes); 
}; 

Edit:with overloads.

Sztuczka polegająca na użyciu nieprawidłowych elementów size to struktura really_has. Robię nie udaje, że jest doskonały, choć ...

w C++ 11, things are simpler (choć nie mniej gadatliwy), ponieważ można wykryć rzeczy przez użytku bezpośrednio. Równowartość cecha jest tak:

template <typename T> 
class has_size { 
private: 
    typedef char Yes; 
    typedef Yes No[2]; 

    template<typename C> static auto Test(void*) 
    -> decltype(size_t{std::declval<C const>().size()}, Yes{}); 

    template<typename> static No& Test(...); 

public: 
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes); 
}; 

jednak zalecana metoda w C++ jest nie używać cech jeśli możesz; w funkcjach można na przykład użyć decltype bezpośrednio w podpisie typu.

+0

Niestety jestem zobowiązany do C++ 98 tutaj; czy mogę jakoś zezwolić zarówno na "size_t size()' jak i 'size_t size() const'? – nijansen

+0

@nijansen: możesz, ale czy to ma sens? Zauważ, że jeśli twoja funkcja to 'void doSomething (C const & container)', wówczas wymagane jest użycie 'const' method :). Zobacz edytowaną odpowiedź, aby dowiedzieć się, jak to zrobić. –

+0

Tak, musiałem zmienić to na przekazanie wartości, ponieważ muszę korzystać z bibliotek, które nie bardzo lubią poprawność const ... Wciąż chcę aby moja metapunkcja 'has_size' była kompatybilna z tymi kontenerami biblioteki i pojemniki STL – nijansen

1

Tak:

char (*)[sizeof(&C::size)] 
+3

Jest całkowicie niekompletna. Jeśli C nie ma metody "rozmiaru", to zawiedzie (nie ma tutaj SFINAE). Jeśli C ma element "size", który nie jest metodą, to również się nie powiedzie (ta linia "zadziała", ale wybierze niewłaściwego członka). – xryl669

Powiązane problemy