Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 08:53
Оценка:
Есть некий конечный набор пользовательских типов и задача их идентифицировать во время выполнения не используя RTTI.
Для не шаблонных типов это может выглядеть так:

using TypeId = const char *;
struct MyType1{
static constexpr TypeId Id(){
return "1";
}
};
struct MyType2{
static constexpr TypeId Id(){
return "2";
}
};


А как быть с шаблонными типами при условии чтобы функция MyType3::Id() оставалась constexpr

template<typename T>
struct MyType3 {
static constexpr TypeId Id(){
// return ?
}
};


Тип идентификатора TypeId не важен. Варианты без constexpr известны.
Re: Вопрос по идентификации типа (не RTTI)
От: niXman Ниоткуда https://github.com/niXman
Дата: 06.04.19 09:07
Оценка: 1 (1)
https://github.com/Manu343726/ctti
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: Вопрос по идентификации типа (не RTTI)
От: andrey.desman  
Дата: 06.04.19 09:10
Оценка: +1
Здравствуйте, niralex, Вы писали:

N>Есть некий конечный набор пользовательских типов и задача их идентифицировать во время выполнения не используя RTTI.

N>Тип идентификатора TypeId не важен. Варианты без constexpr известны.

https://github.com/Manu343726/ctti

А почему "во время выполнения" и constexpr?
Re[2]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 09:31
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>А почему "во время выполнения" и constexpr?


А почему нет? Хотя бы ради оптимизации скорости.
Зачем каждый раз выполнять один и тот же код при определении типа,
если можно определить один раз при компиляции.
Ведь тип известен на момент компиляции и, теоретически мне кажется, это возможно.
Re: Вопрос по идентификации типа (не RTTI)
От: Pzz Россия https://github.com/alexpevzner
Дата: 06.04.19 09:34
Оценка:
Здравствуйте, niralex, Вы писали:

N>А как быть с шаблонными типами при условии чтобы функция MyType3::Id() оставалась constexpr


Чтобы constexpr вряд ли получится, потому что окончательной информацией об эквиавалентности типов не владеет никто владеет не компилятор, а линкер. А данные, вычисленные линкером, если я не ошибаюсь, в мире C++ константами не считаются.

А так, можно завести в каждом типе статическую переменную, и считать идентификатором типа ее адрес.
Re[2]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 09:43
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>https://github.com/Manu343726/ctti


Пока не увидел там как быть с шаблонными пользовательскими типами
Re[2]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 09:51
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Чтобы constexpr вряд ли получится, потому что окончательной информацией об эквиавалентности типов не владеет никто владеет не компилятор, а линкер. А данные, вычисленные линкером, если я не ошибаюсь, в мире C++ константами не считаются.


Pzz>А так, можно завести в каждом типе статическую переменную, и считать идентификатором типа ее адрес.


Объекты инстанцируются в разных динамических модулях/процессах, используются разные компиляторы, поэтому эти адреса будут отличаться. Если бы все было в одном модуле то хватило бы стандартного RTTI
Re: Вопрос по идентификации типа (не RTTI)
От: so5team https://stiffstream.com
Дата: 06.04.19 11:16
Оценка: 1 (1)
Здравствуйте, niralex, Вы писали:

N>А как быть с шаблонными типами при условии чтобы функция MyType3::Id() оставалась constexpr


N>template<typename T>

N>struct MyType3 {
N> static constexpr TypeId Id(){
N> // return ?
N> }
N>};

Как вариант, можно сделать специализации Id() для конкретных сочетаний шаблонных типов и их параметров: https://wandbox.org/permlink/G4XrK5yp6m3cRUaZ
Re[2]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 11:54
Оценка:
Здравствуйте, so5team, Вы писали:

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


N>>А как быть с шаблонными типами при условии чтобы функция MyType3::Id() оставалась constexpr


N>>template<typename T>

N>>struct MyType3 {
N>> static constexpr TypeId Id(){
N>> // return ?
N>> }
N>>};

S>Как вариант, можно сделать специализации Id() для конкретных сочетаний шаблонных типов и их параметров: https://wandbox.org/permlink/G4XrK5yp6m3cRUaZ

Да, это вариант, только специализаций слишком много писать придется...
Re: Вопрос по идентификации типа (не RTTI)
От: Шахтер Интернет  
Дата: 06.04.19 14:20
Оценка: 1 (1)
Здравствуйте, niralex, Вы писали:

Можно использовать якоря, но у них ограниченное использование в compile-time.


using TypeId = int * ;

template <class T>
struct TypeIdNode
 {
  static int Anchor; 
 };

template <class T>
int TypeIdNode<T>::Anchor;

template <class T>
inline constexpr TypeId TypeIdOf = &TypeIdNode<T>::Anchor ; 

/* main() */

template <int &ref> struct Spec {} ;

int main()
 {
  constexpr TypeId a=TypeIdOf<int>; 
  constexpr TypeId b=TypeIdOf<long>; 

  Spec<*a> va;
  Spec<*b> vb;

  //static_assert( a!=b ); 

  return 0;
 }


Сравнивать в compile-time их нельзя.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Вопрос по идентификации типа (не RTTI)
От: Pzz Россия https://github.com/alexpevzner
Дата: 06.04.19 15:43
Оценка: +1
Здравствуйте, niralex, Вы писали:

N>Объекты инстанцируются в разных динамических модулях/процессах, используются разные компиляторы, поэтому эти адреса будут отличаться. Если бы все было в одном модуле то хватило бы стандартного RTTI


А ты понимаешь, что если тип, как-бы, один и тот же (т.е., происходит из одного и того же исходника), но при этом инстанциирован, скажем, из модулей, собранных разными компиляторами, то по большому счету это разные типы, и, например, применение к экземпляру типа, созданного одим компилятором методов, скомпилированных другим компилятором, может привести к ОЧЕНЬ неожиданным результатам.
Re[4]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 06.04.19 17:42
Оценка:
Здравствуйте, Pzz, Вы писали:

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


N>>Объекты инстанцируются в разных динамических модулях/процессах, используются разные компиляторы, поэтому эти адреса будут отличаться. Если бы все было в одном модуле то хватило бы стандартного RTTI


Pzz>А ты понимаешь, что если тип, как-бы, один и тот же (т.е., происходит из одного и того же исходника), но при этом инстанциирован, скажем, из модулей, собранных разными компиляторами, то по большому счету это разные типы, и, например, применение к экземпляру типа, созданного одим компилятором методов, скомпилированных другим компилятором, может привести к ОЧЕНЬ неожиданным результатам.


А мне не нужно вызывать никаких методов, мне нужны только идентификаторы типов, например в виде char *, которые я буду передавать, сравнивать и т.д.
Re[5]: Вопрос по идентификации типа (не RTTI)
От: Pzz Россия https://github.com/alexpevzner
Дата: 06.04.19 21:46
Оценка:
Здравствуйте, niralex, Вы писали:

N>А мне не нужно вызывать никаких методов, мне нужны только идентификаторы типов, например в виде char *, которые я буду передавать, сравнивать и т.д.


Что такое одинаковый тип? Например, если два типа называются одинаково, они одинаковые?
Re[6]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 07.04.19 04:43
Оценка:
Здравствуйте, Pzz, Вы писали:

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


N>>А мне не нужно вызывать никаких методов, мне нужны только идентификаторы типов, например в виде char *, которые я буду передавать, сравнивать и т.д.


Pzz>Что такое одинаковый тип? Например, если два типа называются одинаково, они одинаковые?


Нет. Я поясню немного контекст...
Все множество типов о которых идет речь, являются оболочками для стандартных типов, включая контейнеры
и выполняют кодирование/декодирование в двоичный специфицированный формат.
Теперь представьте себе RPC, где параметры вызываемых функций кодируются и передаются в этом формате.
Набор вызываемых удаленных функций известен вызывающей стороне и перед связыванием локального вызова с одной из них необходимо проверить соответствие типов аргументов,
Вот в этом месте и нужно сравнить идентификаторы типов. В реальности все сложней, обращение к идентификаторам происходит часто,
поэтому я и хочу чтобы они не вычислялись каждый раз во время выполнения, а были определены при компиляции. Т.е. у каждого модуля может быть своя реализация типа с одинаковым названием,
но Id типа и формат в который они кодируют/декодируют одинаковы. В проекте вообще есть модули на nodejs, которые используют те же типы.
Re: Вопрос по идентификации типа (не RTTI)
От: rg45 СССР  
Дата: 07.04.19 05:39
Оценка: +1
Здравствуйте, niralex, Вы писали:

N>Есть некий конечный набор пользовательских типов и задача их идентифицировать во время выполнения не используя RTTI.

N>Для не шаблонных типов это может выглядеть так:

N>using TypeId = const char *;

N>struct MyType1{
N> static constexpr TypeId Id(){
N> return "1";
N> }
N>};
N>struct MyType2{
N> static constexpr TypeId Id(){
N> return "2";
N> }
N>};


N>А как быть с шаблонными типами при условии чтобы функция MyType3::Id() оставалась constexpr


N>template<typename T>

N>struct MyType3 {
N> static constexpr TypeId Id(){
N> // return ?
N> }
N>};


N>Тип идентификатора TypeId не важен. Варианты без constexpr известны.


Можно вынести идентификацию типов за пределы классов. Это позволит присвоить идентификаторы не только пользовательским типам, но и встроенным. После чего идентификаторы можно будет пробовать как-то комбинировать:

template <typename> struct TypeID;

template<> struct TypeID<int> : std::integral_constant<int, 1> { };
template<> struct TypeID<std::string> : std::integral_constant<int, 2> { };
template<> struct TypeID<MyType1> : std::integral_constant<int, 3> { };
template<> struct TypeID<MyType2> : std::integral_constant<int, 4> { };

template <typename T>
struct TypeID<MyType3<T>> : std::integral_constant<int, 420000 + TypeID<T>::value> {};


P.S. Синтаксический сахар и диагностику можно добавить во вкусу.
--
Отредактировано 07.04.2019 5:59 rg45 . Предыдущая версия . Еще …
Отредактировано 07.04.2019 5:43 rg45 . Предыдущая версия .
Re[2]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 08.04.19 07:37
Оценка:
Здравствуйте, rg45, Вы писали:

R>Можно вынести идентификацию типов за пределы классов. Это позволит присвоить идентификаторы не только пользовательским типам, но и встроенным. После чего идентификаторы можно будет пробовать как-то комбинировать:


R>
R>template <typename> struct TypeID;

R>template<> struct TypeID<int> : std::integral_constant<int, 1> { };
R>template<> struct TypeID<std::string> : std::integral_constant<int, 2> { };
R>template<> struct TypeID<MyType1> : std::integral_constant<int, 3> { };
R>template<> struct TypeID<MyType2> : std::integral_constant<int, 4> { };

R>template <typename T>
R>struct TypeID<MyType3<T>> : std::integral_constant<int, 420000 + TypeID<T>::value> {};
R>


R>P.S. Синтаксический сахар и диагностику можно добавить во вкусу.


Да, это было бы прекрасным решением, но дело в том что есть такие пользовательские типы как template<typename ...T> MyTuple {} и там "как-то комбинировать" не получается, слишком много комбинаций шаблонных типов. Я пришел к выводу, что для идентификатора нужен все-таки массив, но тогда не получается сделать идентификацию constexpr.
А идея с вынесением за пределы классов хорошая, спасибо.
Отредактировано 08.04.2019 8:08 niralex . Предыдущая версия .
Re[7]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 08.04.19 08:12
Оценка:
Отредактировано 08.04.2019 8:20 niralex . Предыдущая версия .
Re[3]: Вопрос по идентификации типа (не RTTI)
От: rg45 СССР  
Дата: 08.04.19 09:42
Оценка: 1 (1)
Здравствуйте, niralex, Вы писали:

R>>Можно вынести идентификацию типов за пределы классов. Это позволит присвоить идентификаторы не только пользовательским типам, но и встроенным. После чего идентификаторы можно будет пробовать как-то комбинировать:


R>>
R>>template <typename> struct TypeID;

R>>template<> struct TypeID<int> : std::integral_constant<int, 1> { };
R>>template<> struct TypeID<std::string> : std::integral_constant<int, 2> { };
R>>template<> struct TypeID<MyType1> : std::integral_constant<int, 3> { };
R>>template<> struct TypeID<MyType2> : std::integral_constant<int, 4> { };

R>>template <typename T>
R>>struct TypeID<MyType3<T>> : std::integral_constant<int, 420000 + TypeID<T>::value> {};
R>>


R>>P.S. Синтаксический сахар и диагностику можно добавить во вкусу.


N>Да, это было бы прекрасным решением, но дело в том что есть такие пользовательские типы как template<typename ...T> MyTuple {} и там "как-то комбинировать" не получается, слишком много комбинаций шаблонных типов. Я пришел к выводу, что для идентификатора нужен все-таки массив, но тогда не получается сделать идентификацию constexpr.

N>А идея с вынесением за пределы классов хорошая, спасибо.

Начиная с C++17 есть fold expressions. Вот они как раз позволят и охватить множество комбинаций, и сохранить constexpr:

template <typename...T>
struct TypeID<MyType3<T...>> : std::integral_constant<int, 420000 + ... + TypeID<T>::value> {};


Ну, понятно, что способ комбинирования нужно додумывать так, чтобы он исключал коллизии и обеспечивал уникальные айдишники.
--
Отредактировано 08.04.2019 9:45 rg45 . Предыдущая версия . Еще …
Отредактировано 08.04.2019 9:43 rg45 . Предыдущая версия .
Re: Вопрос по идентификации типа (не RTTI)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.04.19 14:31
Оценка:
такое нагуглилось: https://github.com/Neargye/nameof

насколько я понял, твой случай это использовать макрос NAMEOF_RAW()(https://github.com/Neargye/nameof#remarks), и к результату применить какоу-нить compile-time hash.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: Вопрос по идентификации типа (не RTTI)
От: niralex  
Дата: 08.04.19 20:06
Оценка:
Здравствуйте, rg45, Вы писали:

R>Начиная с C++17 есть fold expressions. Вот они как раз позволят и охватить множество комбинаций, и сохранить constexpr:


R>
R>template <typename...T>
R>struct TypeID<MyType3<T...>> : std::integral_constant<int, 420000 + ... + TypeID<T>::value> {};
R>


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


С fold expressions знаком. Вопрос как раз в "способе комбинирования". Слишком большое число комбинаций. Например для 15 типов это 15!=1307674368000 комбинаций. А еще типы подобные array<n, TMyType>, где в идентификаторе типа нужно учитывать n типа size_t.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.