Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614

Реализовать шаблонную функцию поиска компонентов

13.09.2016, 08:00. Показов 1591. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем. Такой вопрос:

Есть класс Object и класс Component. У класса Component могут быть наследники RigidBodyComponent, TransformComponent и др. Так же каждый компонент имеет имя, которое задается в конструкторе класса:
C++
1
2
3
4
5
6
7
8
9
Framework :: Component :: Component( Object* object, std :: string nameComponent )
{
    _nameComponent  =   nameComponent;
    _d3dObject      =   d3dObject;
}
 
Framework :: ComponentTransform :: ComponentTransform( Object* object ) : Component( object, "Transform" )
{
}
Класс Object хранит список компонентов вот так:
C++
1
std :: map<std :: string, D3DComponent*> _components;
Нужно написать шаблонный метод в классе Object для поиска компонента по ТИПУ. Тоесть грубо говоря вот так:
C++
1
Component* component = object -> findComponent<RigidBodyComponent>();
Тоесть задаю только тип, и он в map'е должен найти или не найти данный компонент.

Делал так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
T*                          findComponent()
{
    T component(this);
    std :: string name = component.getComponentName();
 
    auto it = _d3dComponents.find( name );
    if( it != _d3dComponents.end() )
        return static_cast<T*>( it -> second );
    else
        return nullptr;
}
Но это полное дерьмо, так как создается временный объект с таким же типом, получаю его имя, а только потом ищу его в map'е. Чушь какая то.

Как лучше реализовать, то что я хочу? Чтобы именно искалось по ТИПУ(скорее всего вообще не нужно это имя компонента тогда)
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
13.09.2016, 08:00
Ответы с готовыми решениями:

Реализовать шаблонную функцию minimum
которая находит минимальный элемент, который хранится в экземпляре шаблонного класса Array, при этом типовой параметр шаблона Array может...

Реализовать шаблонную функцию для обработки заданной матрицы
Переделать двумерный массив в шаблоны функций#include &quot;stdafx.h&quot; #include &lt;cmath&gt; #include &lt;cstdlib&gt; #include &lt;ctime&gt; ...

Реализовать шаблонную функцию (без цикла), выводящую числа от 0 до 100
Помогите, пожалуйста)

17
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
13.09.2016, 09:00
Bretbas, возможно подойдет что-то вроде этого:
Кликните здесь для просмотра всего текста
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
class Component
{
public:
    virtual ~Component() = default;
};
 
class Derived1
    : public Component
{
public:
    static constexpr char const * Name() // функция, связывающая тип и имя
    {
        return "Derived1";
    }
};
class Derived2
    : public Component
{
public:
    static constexpr char const * Name() // функция, связывающая тип и имя
    {
        return "Derived2";
    }
};
 
std::map<std::string, Component *> components; // то, что она тут глобальная, - не суть, это для простоты примера
 
template <typename T>
T * findComponent()
{
    auto it = components.find(T::Name());
    if(it != components.end())
    {
        return static_cast<T *>(it->second);
    }
    return nullptr;
}
http://rextester.com/PIMJD31347
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
13.09.2016, 14:39  [ТС]
DrOffset, да это понятно. Может можно как нибудь без всяких дополнительных статических членов функций и т.п.? Может как нибудь сделать так чтобы название класса само автоматом записывалось через typed.name()? Я пробовал typeid.name() , но оно не фурычит с иерархией классов. То есть даёт не имя класса, а имя базового класса
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
13.09.2016, 15:07
Bretbas, Если у T в конструкторе и деструкторе нет сайдэффектов, то шанс инлайнинга в вашем коде очень высок.
0
 Аватар для Voivoid
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
13.09.2016, 15:32
В любой непонятной ситуации используй паттерн визитор
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
13.09.2016, 18:50  [ТС]
Nosey, я вообще не понял, что ты написал(

Voivoid, так в паттерны визитом тоже самое( так же нужно задавать название класса.

Вот смотрите, пользователь создаёт компонент производный от базового Component. Придётся пользователю при создании класса компонента задавать ему имя. А я хочу реализовать, чтобы система сама определяла название класса, регестрировала его и при поиске ключ был именно этот.
Так вообще реально сделать? Если нет, то я сразу же перейду на другие задачи
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
13.09.2016, 19:55
Цитата Сообщение от Bretbas Посмотреть сообщение
Может как нибудь сделать так чтобы название класса само автоматом записывалось через typed.name()? Я пробовал typeid.name() , но оно не фурычит с иерархией классов.
Так пробовал?
Кликните здесь для просмотра всего текста
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
//clang 3.7.0
 
#include <map>
#include <string>
#include <cassert>
 
class Component
{
public:
    virtual ~Component() = default;
};
 
class Derived1
    : public Component
{
};
class Derived2
    : public Component
{
};
 
std::map<std::string, Component *> components;
 
 
template <typename T>
T * findComponent()
{
    auto it = components.find(typeid(T).name());
    if(it != components.end())
    {
        return static_cast<T *>(it->second);
    }
    return nullptr;
}
 
template <typename T>
void registerComponent(Component * c)
{
    components.emplace(typeid(T).name(), c);
}
 
 
int main()
{
    Derived1 d1;
    registerComponent<Derived1>(&d1);
 
    Derived2 d2;
    registerComponent<Derived2>(&d2);
 
    auto * p1 = findComponent<Derived1>();
    assert(p1 == &d1);
 
    auto * p2 = findComponent<Derived2>();
    assert(p2 == &d2);
}

http://rextester.com/BNAI27181
0
 Аватар для Voivoid
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
13.09.2016, 20:20
Цитата Сообщение от Bretbas Посмотреть сообщение
Voivoid, так в паттерны визитом тоже самое( так же нужно задавать название класса.
Тебе зачем находить объекты нужного типа? Чтобы что-то с ним сделать? Ну так и выполняй нужные действия в visitor'е
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
14.09.2016, 18:16  [ТС]
DrOffset, так не пробовал. Попробую, когда на работе буду

Voivoid, Компоненты хранят только информацию, и прежде чем их использовать, нужно найти их и заполнить данными. А действия с этими компонентами производят системы. А системы хранятся в сцене...и тд тд тд)
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
15.09.2016, 13:32
DrOffset, Почему не:
C++
1
2
3
4
5
template <typename T>
std::enable_if_t<std::is_base_of<Component, T>::value> registerComponent(T * c)
{
    components.emplace(typeid(T).name(), c);
}
И соответственно не надо явно указывать аргумент шаблона: registerComponent(&d1);
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
15.09.2016, 17:14  [ТС]
DrOffset, неее. А можно ли как нибудь сделать, чтобы пользователь при создании компонента вообще никак не вводил его имя? Типа такого:
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
class Component
{
public:
    Component() { _name = typeid(this).name(); }
    virtual ~Component() {}
 
    std :: string getName() const { return _name; }
 
protected:
    std :: string _name;
};
 
class Derived1 : public Component
{
public:
    Derived1() : Component() {}
};
class Derived2 : public Component
{
public:
    Derived2() : Component() {}
};
 
int main()
{
    Derived1 d1;
    std :: string d1Name = d1.getName();    // Должно выдавать Derived1, а выдает Component
  
    Derived2 d2;
    std :: string d2Name = d2.getName();    // Должно выдавать Derived2, а выдает Component
}
Чтобы в конструкторе Component определялся тип производного класса
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
15.09.2016, 20:09
Лучший ответ Сообщение было отмечено Bretbas как решение

Решение

Цитата Сообщение от Bretbas Посмотреть сообщение
А можно ли как нибудь сделать, чтобы пользователь при создании компонента вообще никак не вводил его имя?
Можно так:
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
class Component
{
public:
    Component() 
    { }
    virtual ~Component() 
    { }
 
    virtual std::string getName() const = 0;
};
 
template <typename T>
class ComponentRegister
    : public Component
{
public:
    std::string getName() const
    {
        return typeid(T).name();
    }
};
 
class Derived1 : public ComponentRegister<Derived1>
{
public:
    Derived1() {}
};
class Derived2 : public ComponentRegister<Derived2>
{
public:
    Derived2() {}
};
http://rextester.com/ORSB40399

Кроме того, в ComponentRegister можно засунуть и регистрацию указателя в каком-нибудь синглтоне, для получения его потом по имени.
2
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
16.09.2016, 17:30  [ТС]
DrOffset, вот так уже не плохо...хотя все равно нужно вводить имя класса при создании ну в принципе пойдет Спасибо
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
16.09.2016, 18:19
Цитата Сообщение от Bretbas Посмотреть сообщение
хотя все равно нужно вводить имя класса при создании
Макросы тут помогут.
C++
1
#define DECLARE_COMPONENT(Comp) Comp : public ComponentRegister<Comp>
C++
1
2
3
4
5
class DECLARE_COMPONENT(Derived1)
{
    //...
 
};
Но я бы так делать не стал.
0
 Аватар для Voivoid
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
16.09.2016, 21:20
Цитата Сообщение от Bretbas Посмотреть сообщение
Voivoid, Компоненты хранят только информацию, и прежде чем их использовать, нужно найти их и заполнить данными.
Ну какая разница-то. Говорю ж, используй визитор. Зачем заниматься диспетчирезацией руками, когда для этого есть виртуальные функции.
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
19.09.2016, 19:56  [ТС]
DrOffset, вот решил применить код, который ты написал. Суть в том, что такой подход не решает проблему полностью. К примеру полиморфизм. К примеру компоненты храняться в векторе:
C++
1
std :: vector<Component*> components;
И соответственно пишет ошибку, так как не указан тип шаблона. Но мне не нужно здесь его указывать. Грубо говоря:
C++
1
Component* comp = new SomeComponent();
напишет ошибку, так как он хочет чтобы я писал:
C++
1
Component<SomeComponent>* comp = new SomeComponent();
Добавлено через 52 секунды
Voivoid, честно говоря, я не очень понимаю где визитор может применяться. Точнее понимаю, но в моей системе придется переписывать дохрена чего, чтобы добавить этот паттерн
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.09.2016, 20:03
Цитата Сообщение от Bretbas Посмотреть сообщение
Но мне не нужно здесь его указывать.
Конечно не нужно.
Ты код-то мой внимательно посмотри. У меня Component и ComponentRegister - это разные классы совершенно не случайно. Component - это абстрактный интерфейс, как раз для use-case`ов вроде этого:
Цитата Сообщение от Bretbas Посмотреть сообщение
C++
1
std :: vector<Component*> components;
А ComponentRegister - промежуточный регистратор, используемый только при наследовании. Для автоматической генерации правильной реализации виртуальной функции getName.
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
19.09.2016, 20:43  [ТС]
DrOffset, я вначале не понял зачем этот класс Спасиибо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.09.2016, 20:43
Помогаю со студенческими работами здесь

Реализовать шаблонную функцию, считающую сумму элементов массива на заданном интервале
Программе на заданом интервале нужно посчитать сумму элементов массива: #include&lt;iostream&gt; using namespace std; template...

Реализовать шаблонную функцию нахождения максимального элемента главной диагонали квадратной матрицы
Составьте функцию-шаблон для нахождения максимального элемента главной диагонали квадратной матрицы А (nхn). В главной функции оформите...

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

Передача указателя на шаблонную функцию в другую функцию
Пишу тест для нескольких улучшений квиксорта с измерением времени. Функция benchmark принимает итераторы для диапазона элементов, указатель...

Реализовать функцию поиска подстроки в строке
Напишите метод revpositn, который получает два параметра str1 и str2 типа string и возвращает позицию начала первого появления в str1...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru