2015-12-14 3 views
8

私は(ここhttps://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detectorから)このクラスのアイデアを得ていたと思った:Member Detectorのフォールバックはなぜ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 }; 
}; 

が、私はメンバーdouble MyTestを探していたもので、私の場合に適合させることを試みました。

struct Fallback { double MyTest; }; 

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

が、検出器は関係なく、MyTestにメンバーを持っていたかどうのすべてのクラスの「真の」返していました。だから私は、この行を変更しました。私のような行を変更:

struct Fallback { int MyTest; }; 

と予想通り、それが働きました。

フォールバックは、実際に探しているメンバーのタイプではなく、intでなければならない理由は誰でも説明できますか?ここで

は、私は、二重のようにint型が、YとXを探し例です。

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

私の出力は次のとおりです。

答えて

4

それは、 intである必要はありません。どのようなタイプでも構いません。あなただけのすべての場所で、タイプと名前によって、正しくそれを参照する必要があります。

using Arbitrary = double; 

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

とここ

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

アイデアがあればTXを持っていないということです、 Fallback::Xがあります。タイプによって&U::Xと一致します(1つしかないので、Fallbackに1つあります)。しかし、TXがある場合、ルックアップはあいまいです。したがって、Fallback::Xのタイプは問題ではありません。intは最短のものです。

C++ 11で、これはYakkのcan_applyのようなものと多くの方が簡単であることに注意してください:

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

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

も参照してくださいすべての古いスタイルのメンバーの検出器よりも優れている半ダースの他の方法についてthis question

+0

これはどちらのタイプであっても問題ありませんが、それでも 'double'で動作していないようです(私の最近の編集で私の例を見てください)。 –

+0

@DavidDoriaあなたは '&U :: Y'が必要なところに'&U :: X'があるので。 – Barry

+0

うわー、あなたは私が欲しいものを知るためにコンパイラに正しいことをタイプする必要があることを意味します!申し訳ありませんがノイズのため... –

関連する問題