C++11テンプレート:クラスに指定した名前のメンバー変数があるかどうかをどのように判断しますか?
6088 ワード
クラスに指定されたメンバー関数があることをどのように判断するかは、ネット上で多くの文章を見つけることができます.例えば、次の2つの文章は詳しく書かれています.
《C++11の美》《C++テンプレート、メンバー関数が存在するかどうかを判断し、差別化操作を実現する》
私が今関心を持っているのは、クラスにメンバー変数があることをどのように判断するかです.メンバー変数は配列または他のクラスである可能性があります.上記のメンバー関数を判断する文章を見て、その原理を理解した後、メンバー変数かどうかを判断するのも、あまり差がない道理で、実現は非常に簡単です.
上記のテンプレートは、openclの
gccコンパイル運転結果
cl_int2=1 cl_int2=Pi int=0
vs 2015コンパイル実行結果
cl_int2=1 cl_int2=int * __ptr64 int=0
注:テンプレート関数の文
完全に可能です(gccでもvs 2015でも).しかし配列タイプの変数については,上記の書き方ではgccでコンパイルは通過できるが,実行結果は誤りである.たぶんgccは返す値が
このテンプレート関数を複数回用いて異なるメンバー変数を判断する必要がある場合,マクロを用いて上記のコードを改善する必要がある.
このテンプレートをマクロとして定義した後、sメンバーがいるかどうかを確認するには、sをパラメータとして
xメンバーが存在するかどうかを確認するには、xをパラメータとして
《C++11の美》《C++テンプレート、メンバー関数が存在するかどうかを判断し、差別化操作を実現する》
私が今関心を持っているのは、クラスにメンバー変数があることをどのように判断するかです.メンバー変数は配列または他のクラスである可能性があります.上記のメンバー関数を判断する文章を見て、その原理を理解した後、メンバー変数かどうかを判断するのも、あまり差がない道理で、実現は非常に簡単です.
/* , T 's' * value bool * type s (value true ) */
template<typename T>
struct has_member_s{
template <typename _T>
static auto check(_T)->typename std::decay<decltype(_T::s)>::type;
static void check(...);
using type=decltype(check(std::declval()));
enum{value=!std::is_void::value};
};
上記のテンプレートは、openclの
cl_int2
ベクトルタイプの例として、クラス内のsという名前のメンバーがあるかどうかを確認するために使用されます.以下はcl_int2
の定義です./* ---- cl_intn ---- */
typedef union
{
cl_int CL_ALIGNED(8) s[2];
#if __CL_HAS_ANON_STRUCT__
__CL_ANON_STRUCT__ struct{ cl_int x, y; };
__CL_ANON_STRUCT__ struct{ cl_int s0, s1; };
__CL_ANON_STRUCT__ struct{ cl_int lo, hi; };
#endif
#if defined( __CL_INT2__)
__cl_int2 v2;
#endif
}cl_int2;
cl_int2
にs配列という名前が表示されます.次はテストコードです.#include
#include
int main(int argc, char * argv[]){
cout<<"cl_int2="<::value<cout << "cl_int2=" << typeid(has_member_s::type).name() << endl;
cout<<"int="<int>::value<//
}
gccコンパイル運転結果
cl_int2=1 cl_int2=Pi int=0
vs 2015コンパイル実行結果
cl_int2=1 cl_int2=int * __ptr64 int=0
注:テンプレート関数の文
static auto check(_T)->typename std::decay(_T::s)>::type;
decltype(_T::s)
はすでに_T::s
のタイプを取得しており、std::decay
でもう1階をカバーするのは余計なようですが、そうではありません.非配列メンバー変数については、std::decay
のレイヤを削除し、直接static auto check(_T)->decltype(_T::s);
完全に可能です(gccでもvs 2015でも).しかし配列タイプの変数については,上記の書き方ではgccでコンパイルは通過できるが,実行結果は誤りである.たぶんgccは返す値が
int[2]
のような配列ではなく,ポインタしかないと考えている.static auto check(_T)->cl_int[2]; // `std::decay` , ,
static auto check(_T)->cl_int*; // `std::decay` , ,
このテンプレート関数を複数回用いて異なるメンバー変数を判断する必要がある場合,マクロを用いて上記のコードを改善する必要がある.
/* , T 's' * value bool * type s (value true ) */
#define has_member(s) \
template<typename T>\
struct has_member_##s{\
template <typename _T>static auto check(_T)->typename std::decay<decltype(_T::s)>::type;\
static void check(...);\
using type=decltype(check(std::declval()));\
enum{value=!std::is_void::value};\
};
このテンプレートをマクロとして定義した後、sメンバーがいるかどうかを確認するには、sをパラメータとして
has_member
を展開します.has_member(s);
xメンバーが存在するかどうかを確認するには、xをパラメータとして
has_member
を展開します.has_member(x);