2015-12-14 9 views
8

ho pensato che fosse l'idea di questa classe (da qui https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector):Perché il fallback di Member Detector deve essere int?

template<typename T> 
class DetectX 
{ 
    struct Fallback { int X; }; // add member name "X" 
    struct Derived : T, Fallback { }; 

    template<typename U, U> struct Check; 

    typedef char ArrayOfOne[1]; // typedef for an array of size one. 
    typedef char ArrayOfTwo[2]; // typedef for an array of size two. 

    template<typename U> 
    static ArrayOfOne & func(Check<int Fallback::*, &U::X> *); 

    template<typename U> 
    static ArrayOfTwo & func(...); 

    public: 
    typedef DetectX type; 
    enum { value = sizeof(func<Derived>(0)) == 2 }; 
}; 

ma ho cercato di adattarlo al mio caso in cui ero alla ricerca di un membro double MyTest. Così ho cambiato questa linea:

struct Fallback { int X; }; // add member name "X" 

a

struct Fallback { double MyTest; }; 

ma il rilevatore tornavo "true" per tutte le classi a prescindere se avessero un membro Mytest o meno. Ho cambiato la riga in:

struct Fallback { int MyTest; }; 

e quindi ha funzionato come previsto.

Qualcuno può spiegare perché il fallback deve essere un int piuttosto che il tipo di membro che si sta effettivamente cercando?

Ecco un esempio in cui cerco X come un int, ma Y come una doppia:

#include <iostream> 
#include <vector> 

// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector 

// Standard point representation 
struct Point3 
{ 
    double X,Y,Z; 
}; 

struct SomethingElse{}; 

template<typename T> 
class DetectX 
{ 
    struct Fallback { int X; }; // add member named "X" 
    struct Derived : T, Fallback { }; 

    template<typename U, U> struct Check; 

    typedef char ArrayOfOne[1]; // typedef for an array of size one. 
    typedef char ArrayOfTwo[2]; // typedef for an array of size two. 

    template<typename U> 
    static ArrayOfOne & func(Check<int Fallback::*, &U::X> *); 

    template<typename U> 
    static ArrayOfTwo & func(...); 

    public: 
    typedef DetectX type; 
    enum { value = sizeof(func<Derived>(0)) == 2 }; 
}; 

template<typename T> 
class DetectY 
{ 
    struct Fallback { double Y; }; // add member named "Y" 
    struct Derived : T, Fallback { }; 

    template<typename U, U> struct Check; 

    typedef char ArrayOfOne[1]; // typedef for an array of size one. 
    typedef char ArrayOfTwo[2]; // typedef for an array of size two. 

    template<typename U> 
    static ArrayOfOne & func(Check<double Fallback::*, &U::X> *); 

    template<typename U> 
    static ArrayOfTwo & func(...); 

    public: 
    typedef DetectY type; 
    enum { value = sizeof(func<Derived>(0)) == 2 }; 
}; 

int main() 
{ 
    std::cout << DetectX<Point3>::value << " " << DetectX<SomethingElse>::value << std::endl; 

    std::cout << DetectY<Point3>::value << " " << DetectY<SomethingElse>::value << std::endl; 

    return 0; 
} 

La mia uscita è:

risposta

4

E ' non deve essere int. Può essere di qualsiasi tipo Devi solo fare riferimento ad esso in modo corretto, in base al tipo e il nome, in ogni luogo:

using Arbitrary = double; 

struct Fallback { Arbitrary X; }; // <== arbitrary type, specific name X 

e qui:

template<typename U> 
static ArrayOfOne & func(Check<Arbitrary Fallback::*, &U::X> *); 
//        ↑↑↑↑↑↑↑↑↑↑    ↑↑↑ 
//        this type    this name 

L'idea è che se T non ha un X, troverai Fallback::X, che corrisponderà a &U::X per tipo (poiché ce n'è solo uno, quello in Fallback). Ma se T ha uno X, la ricerca sarà ambigua. Quindi non importa che tipo Fallback::X ha - int è solo il più corto.

Si noti che in C++ 11, questo è molto più facile con qualcosa come can_apply di Yakk:

template <class T> 
using x_type = decltype(&T::X); 

template <class T> 
using has_x = can_apply<x_type, T>; 

Vedi anche this question per altri mezza dozzina di modi che sono tutti meglio del rilevatore membro vecchio stile .

+0

Ora ho capito che non dovrebbe importare quale tipo sia, ma ancora non sembra funzionare con 'double' (vedi il mio esempio nella mia recente modifica). –

+0

@DavidDoria Perché hai '& U :: X' dove devi avere' & U :: Y'. – Barry

+0

Wow, vuoi dire che devo scrivere la cosa giusta per il compilatore per sapere cosa voglio !? Scusa per il rumore ... –

Problemi correlati