Информация об изменениях

Сообщение Re: Вопрос по идентификации типа (не RTTI) от 12.04.2019 5:50

Изменено 12.04.2019 7:40 niralex

Re: Вопрос по идентификации типа (не RTTI)
Нашел идею решения своего первоначального вопроса. Может кому-то понадобится...

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

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

В качестве идентификатора типа берем std::array.
Для шаблонных типов делаем constexpr-конкатенацию array

// Реализацию функции join берем отсюда(спасибо автору Klemens Morgenstern): https://gist.github.com/klemens-morgenstern/b75599292667a4f53007
template<typename T, std::size_t L, std::size_t R>
constexpr std::array<T, L+R> join(std::array<T, L> rhs, std::array<T, R> lhs) {...};

struct IntCodec
{
    static constexpr auto Id() { return array<int8_t,1>{1}; }
    // ...
};

struct CharCodec
{
    static constexpr auto Id() { return array<int8_t,1>{2}; }
    // ...
};

template<typename T>
struct VectorCodec
{
    static constexpr auto Id() 
    { 
        return join(array<int8_t,1>{3}, T::Id());  
    }
    // ...
};

int main()
{
    constexpr auto id1 = IntCodec::Id();  // 1
    constexpr auto id1 = VectorCodec<CharCodec>::Id(); // 3,2
    constexpr auto id2 = VectorCodec<VectorCodec<IntCodec>>::Id(); // 3,3,1
    return 0;
}

В результате идентификация типов происходит в compile-time! Мелочь, но приятная
Идентификаторы затем можно сериализовывать, передавать между модулями, сравнивать и т.д.
Буду благодарен, если кто укажет на ошибки, потенциальные проблемы, предложит улучшения, альтернативы.


P.s.
Небольшие косметические улучшения:
Написал функцию MakeTypeId(1), чтобы вместо return array<int8_t,1>{1} писать MakeTypeId(1);
template <typename... Types>
constexpr auto MakeTypeId(Types&&... t)
{
    return std::array<int8_t, sizeof...(Types)>{ std::forward<Types>(t)... };
}


И написал более компактную функцию join, которую можно использовать для объединения не двух, а любого числа array:
template<typename... TArrs>
constexpr auto join(TArrs&&... arrs)
{
    std::size_t i = 0;
    std::array<int8_t, (arrs.size() + ...)> ret{};
    ([&](const auto& arr)
     {
        for (const int8_t& val : arr)
            ret[i++] = val;
     }(arrs), ...);
    return ret;
}
Re: Вопрос по идентификации типа (не RTTI)
Нашел идею решения своего первоначального вопроса. Может кому-то понадобится...

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

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

В качестве идентификатора типа берем std::array.
Для шаблонных типов делаем constexpr-конкатенацию array

// Реализацию функции join берем отсюда(спасибо автору Klemens Morgenstern): https://gist.github.com/klemens-morgenstern/b75599292667a4f53007
template<typename T, std::size_t L, std::size_t R>
constexpr std::array<T, L+R> join(std::array<T, L> rhs, std::array<T, R> lhs) {...};

struct IntCodec
{
    static constexpr auto Id() { return array<int8_t,1>{1}; }
    // ...
};

struct CharCodec
{
    static constexpr auto Id() { return array<int8_t,1>{2}; }
    // ...
};

template<typename T>
struct VectorCodec
{
    static constexpr auto Id() 
    { 
        return join(array<int8_t,1>{3}, T::Id());  
    }
    // ...
};

int main()
{
    constexpr auto id1 = IntCodec::Id();  // 1
    constexpr auto id1 = VectorCodec<CharCodec>::Id(); // 3,2
    constexpr auto id2 = VectorCodec<VectorCodec<IntCodec>>::Id(); // 3,3,1
    return 0;
}

В результате идентификация типов происходит в compile-time! Мелочь, но приятная
Идентификаторы затем можно сериализовывать, передавать между модулями, сравнивать и т.д.
Буду благодарен, если кто укажет на ошибки, потенциальные проблемы, предложит улучшения, альтернативы.


P.s.
Небольшие косметические улучшения:
Написал функцию MakeTypeId(1), чтобы вместо return array<int8_t,1>{1} писать MakeTypeId(1);
template <typename... Types>
constexpr auto MakeTypeId(Types&&... t)
{
    return std::array<int8_t, sizeof...(Types)>{ std::forward<Types>(t)... };
}


И написал более компактную функцию join, которую можно использовать для объединения не двух, а любого числа array:
template<typename... TArrs>
constexpr auto join(const TArrs&... arrs)
{
    std::size_t i = 0;
    std::array<int8_t, (arrs.size() + ...)> ret{};
    ([&](const auto& arr)
     {
        for (const int8_t& val : arr)
            ret[i++] = val;
     }(arrs), ...);
    return ret;
}