2016-04-13 14 views
2

this questionと同じタイトルを意図的に使用しています。私が受け入れる答えが、私が抱いている問題を説明していないと感じているからです。クラスに特定のメンバー変数が実際に存在するかどうかを検出するにはどうすればよいですか?

いくつかのクラスにいくつかのメンバーがあるかどうかを検出する方法を探しています変数です。私が変数を探していますが、それはメンバー関数ではなく、他のものではありません。ここで

は、私がリンクされ、質問に提供された例である。

template<typename T> struct HasX { 
    struct Fallback { int x; }; // introduce member name "x" 
    struct Derived : T, Fallback { }; 

    template<typename C, C> struct ChT; 

    template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1]; 
    template<typename C> static char (&f(...))[2]; 

    static bool const value = sizeof(f<Derived>(0)) == 2; 
}; 

struct A { int x; }; 
struct B { int X; }; 

int main() { 
    std::cout << HasX<A>::value << std::endl; // 1 
    std::cout << HasX<B>::value << std::endl; // 0 
} 

しかし、我々は、我々は

template<typename T> struct HasX { 
    struct Fallback { int x; }; // introduce member name "x" 
    struct Derived : T, Fallback { }; 

    template<typename C, C> struct ChT; 

    template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1]; 
    template<typename C> static char (&f(...))[2]; 

    static bool const value = sizeof(f<Derived>(0)) == 2; 
}; 

struct A { 
    void x() 
    { 
    } 
}; 
struct B { int X; }; 

int main() { 
    std::cout << HasX<A>::value << std::endl; // 1 
    std::cout << HasX<B>::value << std::endl; // 0 
} 

(ような何かを行う場合は、2番目の例であることに注意してください非常に同じ出力が得られますAint xをメンバ関数void x()に置き換えました。

この問題を回避するには実際の考え方はありません。

template <bool, typename> class my_helper_class; 

template <typename ctype> class my_helper_class <true, ctype> 
{ 
    static bool const value = std :: is_member_object_pointer <decltype(&ctype :: x)> :: value; 
}; 

template <typename ctype> class my_helper_class <false, ctype> 
{ 
    static bool const value = false; 
}; 

template <typename T> struct HasX 
{ 
// ... 

static bool const value = my_helper_class <sizeof(f <Derived>(0)) == 2, T> :: value; 
}; 

実際に私がオブジェクトを使用しているかどうかを選択します。しかし、私のクラスに同じ名前のxというオーバーロードされた関数があると、上記は機能しません。私は

struct A 
{ 
    void x() 
    { 
    } 

    void x(int) 
    { 
    } 
}; 

を行う場合たとえば

はその後ポインタが正常に解決されていないとHasX <A>への呼び出しはコンパイルされません。

私は何をすべきですか?これを行うための回避策や簡単な方法はありますか?

+0

ブーストでis_functionがあります。あなたはこれを使うことができるかもしれない。 – Ivan

答えて

2

HasXは、の名前がxであるかどうかをチェックするだけです。 &C::xの場合はが選択されます(とTの両方に一致する場合は、)。 ChT<>のオーバーロードは、&C::xが正確にFallback::xの場合にのみ選択されます。実際にはT::xのタイプをチェックしているわけではないので、実際にはxが変数か関数なのかどうかは決して確認しません。

解決策がある:C++ 11を使用し、ちょうど&T::xはメンバオブジェクトのポインタであることを確認してください:&T::xは、存在する置換の失敗と私たちは、主テンプレートにフォールバックとfalse_typeを取得していない場合は

template <class T, class = void> 
struct HasX 
: std::false_type 
{ }; 

template <class T> 
struct HasX<T, 
    std::enable_if_t< 
     std::is_member_object_pointer<decltype(&T::x)>::value> 
    > 
: std::true_type { }; 

&T::xが存在するが、オーバーロードされた名前の場合、置換は失敗します。 &T::xが存在するがオーバーロードされていない関数の場合は、置換の失敗はenable_if_t<false>です。 SFINAE勝利のために。これらのタイプのすべてのために働く

struct A { 
    void x() 
    { 
    } 

    void x(int) 
    { 
    } 
}; 

struct B { int X; }; 
struct C { int x; }; 
struct D { char x; }; 

int main() { 
    static_assert(!HasX<A>::value, "!"); 
    static_assert(!HasX<B>::value, "!"); 
    static_assert(HasX<C>::value, "!"); 
    static_assert(HasX<D>::value, "!"); 
} 
+0

@MatteoMontiまあ、ええ、 'D :: x'は' char'で、 'int'にしたいですか?また、あまりにも多くのスペース!ちょうど 'std :: cout << HasX :: value' please ... – Barry

+0

わかりました。私が必要とするのは、その名前のメンバ変数をキャッチすることです!整数である必要はありませんが、変数でなければなりません!テストは 'C'と' D'に真実を返すべきです。構造体の残りの部分についてはfalseです。 –

+0

'' X''の型であるべきことがわからないという事実は、私が道を工夫するのを困難にします'&T :: X'が解決されたかどうかを検出できるように' ChT'を使います。私は '&T :: X'の型が何であるか知っていなければなりません。 'decltype'を使うと'&T :: X'が解決されなければエラーになります。だから私たちは何をすることができますか? –

関連する問題