Сопоставление классу уникального числового ID
От: A13x США  
Дата: 19.01.22 23:57
Оценка:
Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.

Помню в MSVC был некий эквивалент аннотации класса, когда можно было сопоставить uuid классу и удобным образом его получить обратно, что давало возможным иметь относительно "безопасную" конвертацию из void* в указатель на класс.

Мне нужно сходное, причем можно даже если для такого рода классов forward declaration сделаны в одном и том же файле.

Самое простое, что можно придумать в части такого сопоставления вероятно выглядит как просто определение некоторого уникального MyRealID прямо в теле класса. В этом случае не нравится:


Чуть сложнее:

// classids.h

template<class T>
struct ID {};

class SomeClass1;
template<>
struct ID<SomeClass1> {
  static const int Value = 1; // be careful to avoid duplicate IDs
};

class SomeClass2;
template<>
struct ID<SomeClass2> {
  static const int Value = 2; // be careful to avoid duplicate IDs
};


// someclass1.h
class SomeClass1 {
public:
  static const int MyRealID = ID<SomeClass1>::Value;
};


// someclass2.h
class SomeClass2 {
public:
  static const int MyRealID = ID<SomeClass2>::Value;
};


в этом случае "uuidof" примерно эквивалентен записи SomeClass1::MyRealID либо ID<SomeClass1>::Value для последнего достаточно включения classids.h без включения самого определения класса someclass1.h

Можно ли сделать чуть более элегантнее и/ли проще? В последнем случае можно было бы вероятно использовать compile time counter, который проскальзывал на rsdn сколько-то лет назад, не уверен есть ли какая-то стандартная альтернатива.

Нужно для gcc, c++17.
Re: Сопоставление классу уникального числового ID
От: TailWind  
Дата: 20.01.22 04:26
Оценка:
Вам нужна фабрика, которая может по ULONG найти класс, сделать ему new и вернуть указатель?
Re: Сопоставление классу уникального числового ID
От: Maniacal Россия  
Дата: 20.01.22 05:56
Оценка:
Здравствуйте, A13x, Вы писали:

A>Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.


А как насчёт C++ RTTI?
Функция typeid().hash_code вернёт уникальный цифровой код для класса.
Re: Сопоставление классу уникального числового ID
От: night beast СССР  
Дата: 20.01.22 06:44
Оценка:
Здравствуйте, A13x, Вы писали:

A>Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.


std::type_info/std::type_index

ну а так можно свое навелосипедить:
struct TypeInfo {};

template<typename T>
struct TypeInfoImpl : TypeInfo {
    static const TypeInfo id;
};

template<typename T>
const TypeInfo TypeInfoImpl<T>::id = {};

struct Test {
   static const TypeInfo& get_id() { return TypeInfoImpl<Test>::id; } 
};


адрес &TypeInfoImpl<Test>::id можно использовать как шаблонный параметр и если не делать динамические либы, то он должен быть один.
Re[2]: Сопоставление классу уникального числового ID
От: A13x США  
Дата: 20.01.22 07:30
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Здравствуйте, A13x, Вы писали:


M>А как насчёт C++ RTTI?

M>Функция typeid().hash_code вернёт уникальный цифровой код для класса.

hash_code же не уникальный. По той же ссылке:

No other guarantees are given: std::type_info objects referring to different types may have the same hash code

Re[2]: Сопоставление классу уникального числового ID
От: A13x США  
Дата: 20.01.22 07:32
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, A13x, Вы писали:


A>>Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.


NB>std::type_info/std::type_index


вроде type_index не обязательно по стандарту int или long — https://en.cppreference.com/w/cpp/types/type_index особенно учитывая, что в с++20 удалили operator!= — хоть и добавили 3-way comparison. Хотя разумно предположить, что на всех мыслимых компиляторах с поддержкой rtti он таким и является. Спасибо, посмотрю плотнее.

NB>ну а так можно свое навелосипедить:

NB>
NB>struct TypeInfo {};

NB>template<typename T>
NB>struct TypeInfoImpl : TypeInfo {
NB>    static const TypeInfo id;
NB>};

NB>template<typename T>
NB>const TypeInfo TypeInfoImpl<T>::id = {};

NB>struct Test {
NB>   static const TypeInfo& get_id() { return TypeInfoImpl<Test>::id; } 
NB>};
NB>


NB>адрес &TypeInfoImpl<Test>::id можно использовать как шаблонный параметр и если не делать динамические либы, то он должен быть один.


если я ничего не упустил, похоже, что в принципе то же самое, что и мой второй вариант, хотя здесь "TypeInfo" не является целым типом.
Отредактировано 20.01.2022 7:44 A13x . Предыдущая версия .
Re[2]: Сопоставление классу уникального числового ID
От: A13x США  
Дата: 20.01.22 07:36
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>Вам нужна фабрика, которая может по ULONG найти класс, сделать ему new и вернуть указатель?


нет, скорее для безопасных кастов, ближайший аналог — это CComQIPtr или ATL-овская обертка над QueryInterface.
Re[3]: Сопоставление классу уникального числового ID
От: Maniacal Россия  
Дата: 20.01.22 07:50
Оценка:
Здравствуйте, A13x, Вы писали:

A>hash_code же не уникальный. По той же ссылке:


A>

A>No other guarantees are given: std::type_info objects referring to different types may have the same hash code

std::type_info.name точно уникальный, но задача, как я понял, была цифровой код иметь.
Re[3]: Сопоставление классу уникального числового ID
От: night beast СССР  
Дата: 20.01.22 08:08
Оценка:
Здравствуйте, A13x, Вы писали:

NB>>адрес &TypeInfoImpl<Test>::id можно использовать как шаблонный параметр и если не делать динамические либы, то он должен быть один.


A>если я ничего не упустил, похоже, что в принципе то же самое, что и мой второй вариант,


второй это какой?

A>хотя здесь "TypeInfo" не является целым типом.


не является и нет необходимости указывать это значение для каждого типа. в качестве значения использовать адрес ид.
compile time counter вроде бы хак, ну и в разных единицах трансляции значения для одного типа разными могут быть.
Отредактировано 20.01.2022 8:16 night beast . Предыдущая версия .
Re[3]: Сопоставление классу уникального числового ID
От: night beast СССР  
Дата: 20.01.22 08:12
Оценка:
Здравствуйте, A13x, Вы писали:

NB>>std::type_info/std::type_index


A>вроде type_index не обязательно по стандарту int или long


насколько помню, это обертка над &std::type_info (который тоже в разных единицах трансляции должен быть один)
зачем тебе int/long не совсем понятно.
Re[3]: Сопоставление классу уникального числового ID
От: TailWind  
Дата: 20.01.22 14:07
Оценка: 1 (1) +2
A>нет, скорее для безопасных кастов, ближайший аналог — это CComQIPtr или ATL-овская обертка над QueryInterface.

Что-то ты недоброе затеял
Почему не стандартный dynamic_cast?
И указатель на базовый класс вместо *void
Re: Сопоставление классу уникального числового ID
От: koenjihyakkei Россия  
Дата: 20.01.22 19:45
Оценка: 2 (1) +1
Здравствуйте, A13x, Вы писали:

Легко же гуглится, например https://www.codeproject.com/Tips/485120/Unique-Identifier-for-Class-in-Cplusplus

Основная идея — использовать адрес статической функции в качестве id.
Re: Сопоставление классу уникального числового ID
От: kov_serg Россия  
Дата: 20.01.22 20:31
Оценка: 18 (2) +2
Здравствуйте, A13x, Вы писали:

A>Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.

A>Нужно для gcc, c++17.
Так сойдёт?
#include <cstddef>
#include <iostream>

template<class T>ptrdiff_t class_id();

static const ptrdiff_t class_id_0=(ptrdiff_t)class_id<void>;

template<class T>ptrdiff_t class_id() {
    return (ptrdiff_t)(class_id<T>)-class_id_0; 
}

class A {};
class B {};

int main(int argc, char const *argv[]) {
    std::cout<<"A="<<class_id<A>()<<"\n";
    std::cout<<"B="<<class_id<B>()<<"\n";
    std::cout<<"void="<<class_id<void>()<<"\n";
    std::cout<<"char*="<<class_id<char*>()<<"\n";
    std::cout<<"const char*="<<class_id<const char*>()<<"\n";
    std::cout<<"char const*="<<class_id<char const*>()<<"\n";
    std::cout<<"char *const="<<class_id<char *const>()<<"\n";
    return 0;
}

A=15
B=45
void=0
char*=75
const char*=105
char const*=105
char *const=135
Отредактировано 20.01.2022 20:38 kov_serg . Предыдущая версия . Еще …
Отредактировано 20.01.2022 20:37 kov_serg . Предыдущая версия .
Re[2]: Сопоставление классу уникального числового ID
От: A13x США  
Дата: 20.01.22 23:16
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, A13x, Вы писали:


A>>Понадобилось нечто сходное com-овскому IID: с более простым требованием, что классу сопоставляется некоторое уникальное число в пределах compilation unit.

A>>Нужно для gcc, c++17.
_>Так сойдёт?
_>
_>#include <cstddef>
_>#include <iostream>

_>template<class T>ptrdiff_t class_id();

_>static const ptrdiff_t class_id_0=(ptrdiff_t)class_id<void>;

_>template<class T>ptrdiff_t class_id() {
_>    return (ptrdiff_t)(class_id<T>)-class_id_0; 
_>}

_>class A {};
_>class B {};

_>int main(int argc, char const *argv[]) {
_>    std::cout<<"A="<<class_id<A>()<<"\n";
_>    std::cout<<"B="<<class_id<B>()<<"\n";
_>    std::cout<<"void="<<class_id<void>()<<"\n";
_>    std::cout<<"char*="<<class_id<char*>()<<"\n";
_>    std::cout<<"const char*="<<class_id<const char*>()<<"\n";
_>    std::cout<<"char const*="<<class_id<char const*>()<<"\n";
_>    std::cout<<"char *const="<<class_id<char *const>()<<"\n";
_>    return 0;
_>}
_>

_>
_>A=15
_>B=45
_>void=0
_>char*=75
_>const char*=105
_>char const*=105
_>char *const=135
_>


Да, должно подойти, как и сказано постом выше вычисления по адресу должно быть достаточным.

Я еще смотрел на attributes, но, похоже это вообще не в ту степь.
Re[4]: Сопоставление классу уникального числового ID
От: Shtole  
Дата: 22.01.22 15:06
Оценка:
Здравствуйте, TailWind, Вы писали:

A>>нет, скорее для безопасных кастов, ближайший аналог — это CComQIPtr или ATL-овская обертка над QueryInterface.


TW>Что-то ты недоброе затеял

TW>Почему не стандартный dynamic_cast?
TW>И указатель на базовый класс вместо *void

Ну, не будем нарушать традиции русскоязычных форумов и в ответ на вопрос объясним топикстартеру, как он не прав!

Недоброе однозначно: все эти игры с uuidof обычно нужны для создания мощной распределённой расширяемой инфраструктуры. Собственно, такой как COM. Где плагины грузились через браузер, а у сисадмина был гуишный тул (OLEViewer) для контроля кишков. Но у такой инфраструктуры и uuidof'ность стандартизированная (QI с типовым switch внутри, либо, собственно, uuidof за счёт MS specific имплементации метаданных). Городить свою такую… в рамках одного приложения… Скорее всего, лучше просто метаданные сделать данными.

А когда я смотрю, как метаданные делают на шаблонах, кровью плакаю.
Do you want to develop an app?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.