Войти
ПрограммированиеФорумОбщее

[C++0x,SFINAE] type has a field (2 стр)

Страницы: 1 2
#15
23:36, 11 сен. 2011

А вот и долгожданный пост про который я говорил в начале темы:

//User types
struct field_t{};
struct other_t{};
typedef int field_type;  // line:4
struct StructA{field_type field;};
struct StructB{other_t other;};
//Implementation detail
template<typename T,typename FIELD_T>
struct type_has_field{
  typedef typename FIELD_T field_t;
  struct yes_type{char padding[1];};
  struct no_type{char padding[8];};
  template<class U,U x>struct test{};
  template<class U>
  static yes_type check(
    U*,
    test<field_t(U::*),&U::field>(*)=nullptr
  );
  template<class U>
  static no_type check(...);
  static const bool value=sizeof(check<T>(0))==sizeof(yes_type);
};

void main(){
  static_assert(
    false==type_has_field<float,field_type>::value,
    "field_type float::field - should not exist"
  );
  static_assert(
    false==type_has_field<char,field_type>::value,
    "field_type char::field - should not exist"
  );
  static_assert(
    true==type_has_field<StructA,field_type>::value,
    "field_type StructA::field - should exist"
  );
  static_assert(
    false==type_has_field<StructB,field_type>::value,
    "field_type StructB::field - should not exist"
  );
}
Он работает на ура, если вот это:
typedef int field_type;  // line:4
не заменять на вот это:
typedef field_t field_type;  // line:4
или это:
typedef other_t field_type;  // line:4


#16
17:00, 14 сен. 2011

по аналогии с http://www.rsdn.ru/forum/cpp/382857.1.aspx

template <class T, T val>
struct member_wrapper{};

template <class T>
char test_for_swap(const T&, member_wrapper<int T::*, &T::field>* p = 0);

template <class T>
double test_for_swap(const T&, ...);

template <class T>
struct has_member_swap
{
    static T t;
    static const bool value = (1 == sizeof(test_for_swap(t)));
};

соответсвенно, has_member_swap<type>::value  константа времени исполнения

вся магия в http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error

#17
20:15, 14 сен. 2011

code_monkey

template<class U>
  static yes_type check(
    U*,
    test<field_t(U::*),&U::field>(*)=nullptr
  );
vs
template <class T>
char test_for_swap(const T&, member_wrapper<int T::*, &T::field>* p = 0);
отличия не существенны.
#18
20:50, 14 сен. 2011

Adler
если у тебя работает для структур, но не работает для простых типов, то можешь составить список простых типов и при помощи него проверять простой ли тип в левом параметре, если да то выдавать сразу false если нет, то проверять твоим методом

#19
21:46, 14 сен. 2011

Pushkoff
ок, ещё раз.
Если надо проверить существование field_type T::field и field_type - простой встроенный тип, то работает правильно.
если field_type - структура или класс, то шаблон type_has_field<T,field_type>::value почти всегда возвращает false, вне зависимости есть ли у T требуемое поле или нету.
Однако если у T есть поле field, но другого типа, то происходит сбой построения. Тоже самое наблюдается если T - унаследован от какой-то структуры у которой есть поле field.

ещё до создания этой темы, я решил проблему породившую эту задачу совсем другим путём(просто добавив в класс T кое-какой статической метод(благо проверить его существование труда не составляет)), обойдя необходимость решать эту задачу, однако интерес к задаче у меня сохранился.
#20
22:36, 14 сен. 2011

Если получится устранить все проблемы и максимально универсализировать, то можно отправить решение в Loki или Boost. Кому-нибудь это точно пригодится.

#21
7:21, 15 сен. 2011

Lamer007
> Если получится устранить все проблемы и максимально универсализировать, то
> можно отправить решение в Loki или Boost.
  А ты уверен, что там этого нет?

#22
9:32, 15 сен. 2011

Zefick
Да вроде нет. Иначе зачем автор это пишет?

Прошло более 2 лет
#23
12:07, 29 окт. 2013

Ура!!!

Нашёл решение(проверенно в MSVC2010):

#include <type_traits>
//User types
struct field_t{};
struct other_t{};
struct StructA{field_t field;};
struct StructB{other_t other;};
struct StructC:public StructA{};
struct StructD:public StructB{};
struct StructT{other_t field;field_t other;};
//Implementation detail
template<typename T,typename FIELD_T>
struct type_has_field{
  __if_not_exists(T::field){
    static const bool value=false;
  }
  __if_exists(T::field){
    static const bool value=std::is_same<FIELD_T,decltype((*(T*)nullptr).field)>::value;
  }
};
//Experiment
void UnitTest(){
  static_assert(
    false==type_has_field<float,field_t>::value,
    "field_t float::field - should not exist"
  );
  static_assert(
    false==type_has_field<char,field_t>::value,
    "field_t char::field - should not exist"
  );
  static_assert(
    true==type_has_field<StructA,field_t>::value,
    "field_t StructA::field - should exist"
  );
  static_assert(
    false==type_has_field<StructB,field_t>::value,
    "field_t StructB::field - should not exist"
  );
  static_assert(
    true==type_has_field<StructC,field_t>::value,
    "field_t StructC::field - should exist"
  );  
  static_assert(
    false==type_has_field<StructD,field_t>::value,
    "field_t StructD::field - should not exist"
  );
  static_assert(
    false==type_has_field<StructT,field_t>::value,
    "field_t StructT::field - should not exist"
  );
  static_assert(
    true==type_has_field<StructT,other_t>::value,
    "other_t StructT::field - should exist"
  );
}
int main(){return 0;}

PS: gcc-4.8.1 не поддерживает "__if_exists": http://ideone.com/pckrBS

#24
12:54, 29 окт. 2013

Adler
> не поддерживает "__if_exists"
Зачем юзать ms specific вещи, если и без него можно?
Нагуглилось на stackoverflow. http://ideone.com/Lk5xiP
По вкусу заменить static результат на enum.

#25
13:26, 29 окт. 2013

RPGman
Спасибо. Годная идея.
> Зачем юзать ms specific вещи, если и без него можно?
Без него не всегда работает:
http://ideone.com/1uwtY6

Пока ещё не понял почему.

#26
14:08, 29 окт. 2013

Понял почему не работает вот это:
http://ideone.com/YMlWLZ

Судя вот по этой ошибке:
http://ideone.com/ZvllSs

prog.cpp:11:65: error: reference to ‘type_has_field<StructT, field_t>::Derived::field’ is ambiguous
Всё что можно проверить этой "конструкцией с Fallback и Derived" так это существование поля у класса по его имени, но не его тип.

#27
14:30, 29 окт. 2013

Adler
> Всё что можно проверить этой "конструкцией с Fallback и Derived" так это
> существование поля у класса по его имени, но не его тип.
Вопрос в первопосте так и звучал: "Надо проверить есть ли у структуры кое-какое поле(member). " :)

#28
14:51, 29 окт. 2013

Если знаешь в компайлтайм имя, то тип проверить не проблема вроде...

#29
22:33, 29 окт. 2013

glap
> Если знаешь в компайлтайм имя, то тип проверить не проблема вроде...
ага.

RPGman
> Вопрос в первопосте так и звучал: "Надо проверить есть ли у структуры кое-какое
> поле(member). " :)
:)

Сделал версию для gcc:

#include <type_traits>
//User types
struct field_t{};
struct other_t{};
struct StructA{field_t field;};
struct StructB{other_t other;};
struct StructC:public StructA{};
struct StructD:public StructB{};
struct StructT{other_t field;field_t other;};
//Implementation detail
template<typename T,typename FIELD_T>
struct type_has_field{
  struct ok_type{char padding[1];};
  struct no_type{char padding[8];};
  template<class U>
  struct has_field{
    struct Fallback{int field;};
    struct Derived:U,Fallback{};
    template<typename C, C> struct ChT;
    template<typename C> static no_type f(ChT<int Fallback::*,&C::field>(*)=nullptr);
    template<typename C> static ok_type f(...);
    static const bool value=sizeof(ok_type)==sizeof(f<Derived>(0));
  };
  struct FalseStruct{
    template<class U>struct next{typedef FalseStruct type;};
    static const bool value=false;
  };
  struct TrueStruct{
    static const bool value=true;
  };
  struct NextStruct1{
    template<class U>
    struct next{
      static const bool flag=(
        std::is_same<
          FIELD_T,
          decltype((*(U*)nullptr).field)
        >::value
      );
      typedef typename std::conditional<
        flag,
        TrueStruct,FalseStruct
      > type_expr;
      typedef typename type_expr::type type;
    };
  };
  struct NextStruct0{
    template<class U>
    struct next{
      static const bool flag=(
        has_field<U>::value
      );
      typedef typename std::conditional<
        flag,
        NextStruct1,FalseStruct
      > type_expr;
      typedef typename type_expr::type type;
    };
  };
  typedef typename std::conditional<
    std::is_class<T>::value,
    NextStruct0,FalseStruct
  > type_expr0;
  typedef typename type_expr0::type type_expr1;
  typedef typename type_expr1::template next<T> type_expr2;
  typedef typename type_expr2::type type_expr3;
  typedef typename type_expr3::template next<T> type_expr4;
  typedef typename type_expr4::type type_expr5;
  static const bool value=type_expr5::value;
};
//Experiment
static_assert(
  false==type_has_field<float,field_t>::value,
  "field_t float::field - should not exist"
);
static_assert(
  false==type_has_field<char,field_t>::value,
  "field_t char::field - should not exist"
);
static_assert(
  true==type_has_field<StructA,field_t>::value,
  "field_t StructA::field - should exist"
);
static_assert(
  false==type_has_field<StructB,field_t>::value,
  "field_t StructB::field - should not exist"
);
static_assert(
  true==type_has_field<StructC,field_t>::value,
  "field_t StructC::field - should exist"
);  
static_assert(
  false==type_has_field<StructD,field_t>::value,
  "field_t StructD::field - should not exist"
);
static_assert(
  false==type_has_field<StructT,field_t>::value,
  "field_t StructT::field - should not exist"
);
static_assert(
  true==type_has_field<StructT,other_t>::value,
  "other_t StructT::field - should exist"
);
int main(){return 0;}
http://ideone.com/T8R062
Коротко для gcc написать не получилось, так как он постоянно ругался на не хватку typename`ов и "template`ов.

Страницы: 1 2
ПрограммированиеФорумОбщее

Тема в архиве.