652 / 462 / 80
Регистрация: 26.10.2010
Сообщений: 1,263
Записей в блоге: 4
1

[Метапрограммирование] Определить наличие поля определенного типа в объекте переданном в шаблон

13.08.2015, 11:38. Показов 3443. Ответов 7
Метки нет (Все метки)

Здравствуйте форумчане.
Необходимо в шаблоне определить наличие поля определенного типа у объекта, который был передан в шаблон.

Два объекта для примера:
C++
1
2
3
4
5
6
7
8
9
10
11
struct Obj1
{
    int value_1;
    std::string value_2;
};
 
struct Obj2
{
    int value_1;
    std::vector< std::string > names;
};
Шаблон:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template < typename T >
class Foo
{
    Foo() = default;
    void func()
    {
        // Если у T есть поле типа std::vector< std::string > выполнить какие-то действия
        // Если его нет, то ничего не делать.
    }
};
 
//...
 
Foo<Obg1>* obj1 = new Foo<Obj1>();
Foo<Obg2>* obj2 = new Foo<Obj2>();
 
obj1->func();
obj2->func();
С уважением QVO.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.08.2015, 11:38
Ответы с готовыми решениями:

Проверить в JSON наличие определенного поля
Здравствуйте! подскажите, пожалуйста, я посылаю http запрос, в ответ мне приходит json, но он может...

Анализ чертежей, созданных в KOMPAS (SolidWorks) на наличие в нем объектов определенного типа
Доброе время суток, всем! Нужна ваша помощь, может кто-то с чем-то похожим сталкивался. Нужно...

Определить наличие у хранимого типа методов SaveToStream и LoadFromStream
Есть шаблонный динамический массив по назначению аналогичный std::vector Массив имеет методы...

Задание ключом в объекте - значение поля ввода при динамическом создании поля
$(function() { var values = {}; $('&lt;br /&gt;'+ '&lt;input type=&quot;text&quot; class=&quot;field&quot;...

7
В астрале
Эксперт С++
8044 / 4801 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
13.08.2015, 12:40 2
Лучший ответ Сообщение было отмечено QVO как решение

Решение

QVO, http://stackoverflow.com/quest... e-in-class
Но это только если определить есть ли в классе переменная с таким именем. А вот определить, есть ли поле конкретного типа уже значительно сложнее, ибо нужно знание о том, какие типы есть в классе, т.е. нужна рефлексия, которой в С++ нет, но можно к примеру использовать boost::fusion.

Добавлено через 41 минуту
Вот развлекалово с fusion:
http://coliru.stacked-crooked.... fd0ff23425

Добавлено через 6 минут
И чуть покороче с использованием find.
http://coliru.stacked-crooked.... b093d9271d
2
Эксперт С++
8703 / 4287 / 954
Регистрация: 15.11.2014
Сообщений: 9,723
14.08.2015, 03:01 3
Лучший ответ Сообщение было отмечено DrOffset как решение

Решение

Цитата Сообщение от QVO Посмотреть сообщение
Необходимо в шаблоне определить наличие поля определенного типа у объекта, который был передан в шаблон.
1.
способен определить доступность любых членов класса: данных, или методов.

2.
учитывает модификаторы доступа.

3.
способен выполнять поиск членов класса по всей иерархии наследования.

4.
для функций членов умеет различать константные и не константные версии

из недостатков:
есть трудности у компиляторов вижал студии.
2012/2013 студии недостаточно поддерживают с++11
поэтому требуются доработки
(дома где то валяются готовые варианты для этих компиляторов)

старый гцц не учитывает модификатор доступа
http://rextester.com/ISRJE89321

новый гцц, баг исправлен
http://ideone.com/ObElnu

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <iostream>
#include <type_traits>
 
using namespace std;
 
 
#define DETECTED_MEMBER(member_name)                                                      \
template<typename C, typename T>class has_##member_name                                   \
{                                                                                         \
    template<class U> static constexpr auto Check(U*) -> typename                         \
    std::is_same< decltype( std::declval<U>().member_name), T >::type;                    \
                                                                                          \
    template<typename> static constexpr std::false_type Check(...);                       \
    typedef decltype(Check<C>(0)) Result;                                                 \
public:                                                                                   \
    enum { eIS_NOCONST = 0 };                                                             \
    enum { eIS_CONST   = 0 };                                                             \
    enum { eIS_AVAILABLE = Result::value };                                               \
};                                                                                        \
template<class C,typename R, typename... Args>class has_##member_name<C, R(Args...)>      \
{                                                                                         \
    typedef R(C::*Method)(Args...);    typedef R(C::*CMethod)(Args...)const;              \
    template <class U> using NoConst = decltype(static_cast<Method> (&U::member_name));   \
    template <class U> using Const   = decltype(static_cast<CMethod>(&U::member_name));   \
                                                                                          \
    template<class U> static constexpr std::true_type  CheckNoConst( NoConst<U>*p );      \
    template<class>   static constexpr std::false_type CheckNoConst(...);                 \
    typedef decltype(CheckNoConst<C>(0)) NoConstResult;                                   \
                                                                                          \
    template<class U> static constexpr std::true_type  CheckConst( Const<U>*p);           \
    template<class>   static constexpr std::false_type CheckConst(...);                   \
    typedef decltype(CheckConst<C>(0)) ConstResult;                                       \
public:                                                                                   \
    enum { eIS_NOCONST = NoConstResult::value      };                                     \
    enum { eIS_CONST   = ConstResult::value        };                                     \
    enum { eIS_AVAILABLE = eIS_NOCONST | eIS_CONST };                                     \
};
 
#define is_available(class_name, member_type, member_name)         has_##member_name<class_name, member_type>::eIS_AVAILABLE
#define is_available_method(class_name, member_type, member_name)  has_##member_name<class_name, member_type>::eIS_NOCONST
#define is_available_cmethod(class_name, member_type, member_name) has_##member_name<class_name, member_type>::eIS_CONST
 
//------------------------------------------------------------------------------------
 
 
int g;
struct A
{
    A():r(g){}
 
    void fooA(int);
    void fooA(int)const;
    void fooA();
    void fooA()const;
 
    int v;
    int& r;
    int a[10];
    int* p;
    int** pp;
private:
    void private_foo();
};
 
struct B : A
{
    int v;
    int fooB(){ return 0; }
};
 
 
DETECTED_MEMBER(fooA);
DETECTED_MEMBER(fooB);
DETECTED_MEMBER(v);
DETECTED_MEMBER(r);
DETECTED_MEMBER(a);
DETECTED_MEMBER(p);
DETECTED_MEMBER(pp);
 
DETECTED_MEMBER(private_foo);
 
 
int main()
{
    //синтаксис:  is_available(  имя_класса ,  тип_мембера  , имя_мембера)
 
    //вернет true если мембер доступен, иначе - false
 
    //---- детектирование данных
    cout<< "is available int B.v ? "
        << is_available(B,int,v)     <<endl;
 
    cout<< "is available int& B.r ? "
        << is_available(B,int&,r)    <<endl;
 
    cout<< "is available int B.a[10] ? "
        << is_available(B,int[10],a) <<endl;
 
    cout<< "is available int* B.p ? "
        << is_available(B,int*,p)    <<endl;
 
    cout<< "is available int* B.pp ? "
        << is_available(B,int**,pp)  <<endl;
 
    //---- детектирование методов
    cout<< "is available void B.fooA(int) or void B::fooA(int)const ? "
        <<is_available(B,void(int),fooA) <<endl;
 
    cout<< "is available void B.fooA(int) ? "
        << is_available_method(B,void(int),fooA) <<endl;
 
    cout<< "is available void B.fooA(int)const ? "
        << is_available_cmethod(B,void(int),fooA) <<endl;
 
    cout<< "is available int B.fooB() ? "
        << is_available_method(B,int(),fooB) <<endl;
 
    cout<< "is available void B.private_foo() ? "      //<--- bug местного gcc ?? Должно быть 0. Компилятор gcc48_32 отрабатывает корректно
        << is_available(B,void(),private_foo) <<endl;
}
9
279 / 39 / 13
Регистрация: 11.10.2015
Сообщений: 405
05.03.2017, 00:07 4
hoggy, oh my god
0
63 / 35 / 25
Регистрация: 17.07.2014
Сообщений: 457
05.03.2017, 01:03 5
Определяем наличия метода:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template<typename T> struct has_foo {
private:
    static int detect(...);
    template<typename U> static decltype(std::declval<T>().foo(42)) detect(const U&);
public:
    static constexpr bool value = std::is_same<void, decltype(detect(std::declval<T>()))>::value;
};
 
class A {
public:
    void foo(void);
};
 
class B {
public:
    int bar() {
        return 1;
    }
};
 
int main_(){
    if (has_foo<A>::value)
        std::cout << "Yes";
    else
        std::cout << "No";
    system("pause");
}
0
279 / 39 / 13
Регистрация: 11.10.2015
Сообщений: 405
05.03.2017, 01:52 6
maxm, тогда уж лучше так: https://ideone.com/nDlFUE
0
Вездепух
Эксперт CЭксперт С++
10261 / 5558 / 1523
Регистрация: 18.10.2014
Сообщений: 13,551
05.03.2017, 02:41 7
Так а к чему здесь все эти варианты, если ни один из них не отвечает на исходный вопрос? В котором ясно требуется распознать наличие в классе любого поля данного типа. Т.е. указывать конкретное имя поля запрещается.
0
Эксперт С++
8703 / 4287 / 954
Регистрация: 15.11.2014
Сообщений: 9,723
05.03.2017, 11:54 8
Цитата Сообщение от maxm Посмотреть сообщение
Определяем наличия метода:
уппс...

http://rextester.com/VSGAT69880
Код
Error(s):
source_file.cpp: In instantiation of ‘struct has_foo<A>’:
source_file.cpp:26:19:   required from here
source_file.cpp:8:69: error: no matching function for call to ‘A::foo(int)’
     template<typename U> static decltype(std::declval<T>().foo(42)) detect(const U&);
                                                                     ^
source_file.cpp:15:10: note: candidate: void A::foo()
     void foo(void);
          ^
source_file.cpp:15:10: note:   candidate expects 0 arguments, 1 provided
source_file.cpp: In function ‘int main_()’:
source_file.cpp:31:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^
Цитата Сообщение от zarko97 Посмотреть сообщение
тогда уж лучше так:
https://ideone.com/XCTVmP



C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdint>
 
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               \
    template <typename U>                                                   \
    class traitsName                                                        \
    {                                                                       \
    private:                                                                \
        template<typename T, T> struct helper;                              \
        template<typename T>                                                \
        static std::uint8_t check(helper<signature, &funcName>*);           \
        template<typename T> static std::uint16_t check(...);               \
    public:                                                                 \
        static                                                              \
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
    }
 
DEFINE_HAS_SIGNATURE(has_foo, T::foo, void (*)(void));
 
struct StaticFoo 
{
    void foo(); 
    void foo()const; 
};
struct NormalFoo { void foo(); };
struct NoFoo {};
 
static_assert(has_foo<StaticFoo>::value, "Unexpected value");
static_assert(!has_foo<NormalFoo>::value, "Unexpected value");
static_assert(!has_foo<NoFoo>::value, "Unexpected value");
 
int main()
{
    return 0;
}
Код
сообщения компилятора
prog.cpp:27:1: error: static assertion failed: Unexpected value
 static_assert(has_foo<StaticFoo>::value, "Unexpected value");
 ^~~~~~~~~~~~~
Добавлено через 2 минуты
прежде чем выкладывать свои поделия,
вы б хотя бы их проверили
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.03.2017, 11:54
Помогаю со студенческими работами здесь

Написать функцию целого типа, определяющую наличие в первой строке матрицы наличие седловой точки.
ребят нужна помощь Задачи по программированию. Задача решается на двух языках. Задача 4....

Удаление файлов определенного типа из определенного каталога
Нужна помощь! Хочу написать командный файл, который бы удалял определенный тип файлов из...

Преобразование типа в объекте
Доброй ночи! Завис на одном вопросе! Написал простенький код: package les2; import...

Проверка на существование поля в объекте
Получаю ответ от сервера в json формате, как мне проверить существование определенного поля в этом...

Получение текста из поля в объекте
Всем привет! Есть проблема, никак не могу решить: Есть объект канваса Text. У текста есть поле...

Как определить через API наличие у окна приложения наличие модального дочернего
Здравия желаю! Собственно, В названии темы — вопрос. Для пояснения прикрепляю скрин. Интересует...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru