3

特定のクラス T に特定の型 Type を持つ特定の名前のメンバーがあるかどうかをコンパイル時に検出できるクラスを作成する方法を知っています。

#include <type_traits>

template <typename T, typename Type, bool = std::is_class<T>::value>
struct has_member_foo
{
private:
  template <Type T::*> struct helper;

  template <typename U>
  static std::false_type test(...);

  template <typename U>
  static std::true_type test(helper<&U::foo> *);

  typedef decltype(test<T>(nullptr)) testresult;
public:
  static const bool value = testresult::value;
};

template <typename T, typename Type>
struct has_member_foo<T, Type, false> : std::false_type { };

struct Has_Foo
{
  int foo;
};

struct Has_No_Foo
{
  int bar;
};

void test()
{
  static_assert(has_member_foo<Has_Foo, int>::value == true, ":(");
  static_assert(has_member_foo<Has_No_Foo, int>::value == false, ":(");
  static_assert(has_member_foo<int, int>::value == false, ":(");
}

ほとんどの場合、これらの特性を使用したい場合、このメンバーが特定の型に変換可能であるか、整数型であるかなどを気にするため、メンバー変数の正確な型を述べる必要があるのは好きではありません。正確なタイプについて。特定の名前のメンバー変数の存在と型を検出できるようにしたいと考えています。私はこのようなものを書くことができるようにしたいと思います:

static_assert(has_member_foo<T>::value && std::is_integral<typename has_member_foo<T>::type>::value,
              "The type has to have an integral member with name foo");

コンストラクト &T::foo が合法であることがわかっている場合、次のような方法でメンバーのタイプを取得できます

template <typename T, typename U>
T get_member_type(T U::*);

typedef decltype(get_member_type(&T::foo)) the_member_type;

しかし、主にヘルパー構造体がメンバーへのポインターの署名を知る必要があるため、SFINAE で正しい結果を得る 2 つのメソッドの組み合わせを生成することはできません。最終的なコードは、引数として名前を持つプリプロセッサ マクロになるため、どのソリューションでもプリプロセッサを使用できます。

4

2 に答える 2

5

これは、 という名前の変数に対して行う簡単な方法ですid

#include <type_traits>

using namespace std;

template<typename T, typename V = bool>
struct has_id : false_type { };

template<typename T>
struct has_id<T,
    typename enable_if<
        !is_same<decltype(declval<T>().id), void>::value,
        bool
        >::type
    > : true_type
{
    typedef decltype(declval<T>().id) type;
};

使用方法は次のとおりです。

#include <iostream>

using namespace std;

struct X { int id; };

int main()
{
    static_assert(
        has_id<X>::value && is_integral<has_id<X>::type>::value,
        "Error!"
        );
}

マクロを許容できる場合は、物事をさらに簡単にすることができます。

#define DEFINE_MEMBER_CHECKER(member) \
    template<typename T, typename V = bool> \
    struct has_ ## member : false_type { }; \
    template<typename T> \
    struct has_ ## member<T, \
        typename enable_if< \
            !is_same<decltype(declval<T>().member), void>::value, \
            bool \
            >::type \
        > : true_type \
    {  \
        typedef decltype(declval<T>().member) type; \
    };

#define HAS_MEMBER(C, member) \
    has_ ## member<C>::value

#define MEMBER_TYPE(C, member) \
    has_ ## member<C>::type

その後、次のように使用できます。

DEFINE_MEMBER_CHECKER(id)

int main()
{
    static_assert(
        HAS_MEMBER(X, id) && is_integral<MEMBER_TYPE(X, id)>::value,
        "Error!"
        );
}
于 2013-02-18T16:34:49.803 に答える
1
#include <type_traits>

template<typename T>
struct test_code { typedef void type; };

template<typename T>
using TestCode = typename test_code<T>::type;

template<typename T, typename=void>
struct has_member_foo:std::false_type {};
template<typename T>
struct has_member_foo<T,
  TestCode< decltype( std::declval<T>().foo ) >
>:std::true_type
{
  typedef decltype( std::declval<T>().foo ) type;
};
template<typename T>
using FooMemberType = typename has_member_foo<T>::type;

struct test_nofoo {};
struct test_foo { int foo; };

#include <iostream>
int main() {
   std::cout << has_member_foo<test_nofoo>::value << has_member_foo<test_foo>::value << std::is_same<int, FooMemberType<test_foo>>::value << "\n";
}

動作するはずです。コンパイラがテンプレート エイリアスTestCode< decltype( std::declval<T>().foo ) >をまだサポートしていない場合は、typename test_code< decltype( std::declval<T>().foo ) >::type.

于 2013-02-18T16:17:45.853 に答える