2016-04-19 13 views
8

クラスのメンバ変数が静的かどうかを確認したいと思います。 std :: is_member_pointerを使用すると、参照メンバ以外のすべての型で正常に動作します。タイプ特性:参照メンバ変数が静的かどうかを確認してください

#include <type_traits> 

struct A { 
    int foo; 
}; 

struct B : A {}; 

struct C { 
    static int foo; 
}; 

struct D : C { 
}; 

struct E { 
    int &foo; 
}; 

struct F { 
    static int &foo; 
}; 

static_assert(std::is_member_pointer<decltype(&A::foo)>::value, "No"); 
static_assert(std::is_member_pointer<decltype(&B::foo)>::value, "No"); 
static_assert(!std::is_member_pointer<decltype(&C::foo)>::value, "No"); 
static_assert(!std::is_member_pointer<decltype(&D::foo)>::value, "No"); 

// Fail to compile: 
static_assert(std::is_member_pointer<decltype(&E::foo)>::value, "No"); 

static_assert(!std::is_member_pointer<decltype(&F::foo)>::value, "No"); 

Live example.

Iは、ポインタが基準部材を指し示すことができないこと、エラーを理解します。しかし、それを避けて、静的変数か非静的変数かを区別する方法はありますか?それについてのアイデア?

+1

関連:http://stackoverflow.com/questions/8336274/pointer-to-member-that-is-a-reference-illegal – PiotrNycz

答えて

2

あなたは&E::fooがSFINAEを使用して失敗した(と場合E::foo内の別の1が全く存在しない)場合のフォールバックを追加することができます。

このコードは何
template <typename T> 
std::is_member_pointer<decltype(&T::foo)> is_member_foo(int); 

template <typename T> 
decltype(T::foo, std::true_type{}) is_member_foo(long); 

template <typename T> 
std::false_type is_member_foo(...); 

template <typename T> 
using IsMemberFoo = decltype(is_member_foo<T>(0)); 

static_assert(IsMemberFoo<A>{}, "No"); 
static_assert(IsMemberFoo<B>{}, "No"); 
static_assert(!IsMemberFoo<C>{}, "No"); 
static_assert(!IsMemberFoo<D>{}, "No"); 
static_assert(IsMemberFoo<E>{}, "No"); 
static_assert(!IsMemberFoo<F>{}, "No"); 
static_assert(!IsMemberFoo<G>{}, "No"); // struct G { }; 

  • &T::fooがある場合有効であれば、メンバーが静的かどうかをstd::is_member_pointer(ご使用のバージョン)を使用してチェックします。
  • &T::fooが有効でない場合、それは戻って2番目のオーバーロード(ここではあなたがfooが静的​​でない場合、または最初の過負荷が選択されていたであろうことを確信している)にフォール:T::fooが有効な場合(メンバーが存在
    • )、それはstd::true_typeを返します。
    • その他の場合、最後のオーバーロードに戻り、std::false_typeを返します。

は、第3過負荷が選択されるようにprivate部材に、T::fooは、無効ある(@iammilindのおかげで)注意します。

ideone上の実施例:http://ideone.com/FILHbK

サイドノート(拡張説明):

  • &T::fooが有効である場合、2つの最初のオーバーロードが有効であるが、intが正確であるので、最初のものが選択されます一致するのはlongではありません。
  • decltype(T::foo, std::true_type{})T::fooT::fooが有効でない場合、バック3番目のオーバーロードにフォール「SFINAEを聞かせて」するだけここにあるが、結果のタイプはコンマ演算子にstd::true_typeのおかげです。

あなたが好きなら、あなたもジェネリックバージョン(http://ideone.com/lzH2FB)を作成することができます:あなたは(is_member_機能を持たない)クラスのすべてをカプセル化する場合は、これらの2つの答えを参照してください。また

#define IsMember(MEM) \ 
template <typename T> \ 
std::is_member_pointer<decltype(&T::MEM)> is_member_##MEM(int); \ 
template<typename T> \ 
decltype(T::MEM, std::true_type{}) is_member_##MEM(long); \ 
template <typename T> \ 
std::false_type is_member_##MEM(...); \ 
template <typename T> \ 
using IsMember_##MEM = decltype(is_member_##MEM<T>(0)); 

// Instanciate IsMember_foo 
IsMember(foo); 

// Use it: 
static_assert(IsMember_foo<A>{}, "No"); 

を:

+0

あなたの答えは私にとって正しいようです。 Upvotedそれ。サンプルコードにいくつかの変更を加えることができますか? 1.「C」は2回繰り返されますが、「D」はありません。 2. 'typename C'を' typename T'に置き換えます。これは読者のために混乱を招きます(既に 'class C'があります)。サンプルコードとあなたの答えの両方。ところで、あなたのSFINAEの理解は非常に良いですし、上記のようなスタンドアロンコードを作成する代わりに、マクロを使用してコードのようなライブラリを作成する必要があります。また、 'private'変数ではうまくいかないことに注意してください。 – iammilind

+0

@ iammilindありがとう、私は答えとideoneコードを更新しました。 – Holt

+0

ジェネリックメンバーを作成する新しい方法が良いです。しかし、想像してみてください。独占権のためにis_member _ ## MEMをたくさん作成することになります。したがって、クラス内でカプセル化して同じクラスを利用できる方法を考える必要があります。技術的には、たとえ多くのテンプレートを作成しても、間違いはありません。しかし、そうする必要はありません。 'class'の利点は' bool value 'を持つことができます。これは印刷/チェックの目的にも使用できます。 – iammilind

関連する問題