2015-12-14 11 views
8

Myślałam, że coraz ideę tej klasie (stąd https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector):Dlaczego funkcja wykrywania detektora członkowskiego musi być 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 }; 
}; 

ale starałem się dostosować go do mojego przypadku, w którym szukałem członka double MyTest. Więc zmieniłem tę linię:

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

do

struct Fallback { double MyTest; }; 

ale detektor wracał „true” dla wszystkich klas niezależnie od tego, czy mieli człon MyTest czy nie. Zmieniłem linię na:

struct Fallback { int MyTest; }; 

, a następnie działało zgodnie z oczekiwaniami.

Czy ktoś może wyjaśnić, dlaczego awarię musi być int, a nie typ członka, którego faktycznie szukasz?

Oto przykład, gdzie szukać X jako int, ale Y jako podwójny:

#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; 
} 

Moja wyjścia:

Odpowiedz

4

It nie musi być int. Może być dowolnego rodzaju. Po prostu trzeba się do niego poprawnie, według rodzaju i nazwie, w każdym miejscu:

using Arbitrary = double; 

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

i tutaj:

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

Chodzi o to, że jeśli T nie ma X, znajdziesz Fallback::X, który będzie zgodny z &U::X według typu (ponieważ jest tylko jeden - ten w Fallback). Ale jeśli T ma wartość X, wyszukiwanie będzie niejednoznaczne. Nie ma znaczenia, jaki typ Fallback::X ma - najkrótszy.

Należy zauważyć, że w C++ 11, jest to o wiele łatwiejsze z czymś Yakk za can_apply:

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

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

Patrz również this question przez pół tuzina innych sposobów, które mają wszystko lepsze niż detektora zarejestrował się w starym stylu .

+0

Teraz rozumiem, że nie powinien mieć znaczenia, jaki to jest, ale nadal nie działa z "podwójnym" (zobacz mój przykład w mojej ostatniej edycji). –

+0

@DavidDoria Ponieważ masz '& U :: X', gdzie musisz mieć' & U :: Y'. – Barry

+0

Wow, masz na myśli, muszę wpisać właściwą rzecz dla kompilatora, aby wiedzieć, co chcę !? Przepraszamy za hałas ... –

Powiązane problemy