Метафункция для выполнения операции приведения к статическим полиморфным типам std::is_convertible limited

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

Библиотека является частично метапрограммой, и приведенный ниже код является моей попыткой написать функцию, которая может пройтись по полиморфному дереву, чтобы автоматически получить преобразование для

Все участвующие в них классы основаны на статическом полиморфизме на основе CRTP, поэтому никакие виртуальные типы нигде не допускаются, только шаблоны и т. Д.

ЦЕЛЬ T_To* XCast(T_From*)

Вернет приведение указателя T_From к указателю T_T, учитывая, что может потребоваться опросить черты типа, чтобы найти правильные промежуточные приведения, необходимые для перехода от T_From к T_To

C++ 20 обеспечивает интроспекцию базового класса, но с использованием C++17 в Visual Studio я создал тип интерфейса, который должен реализовывать каждый участвующий класс. Этот интерфейс будет определять все, что требуется для работы функции преобразования.

В настоящее время интерфейс содержит

Список типов базовых классов классов в порядке вывода TypeList - это просто структура пакета параметров, в которой хранятся типы, а также размер списка типов и т. Д.

struct I_T_TypeInfo {

    using I_T_BaseList = TypeList<nullptr_t>;

// добавляем в интерфейс все, что требуется для работы конвертации. };

Моя главная проблема заключалась в том, что std::is_Convertible не работает должным образом, как только вы попадаете во время компиляции, шаблоны и рекурсию.

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

Заранее спасибо.

    class IBase {
public:

    struct I_T_TypeInfo {

        using I_T_BaseList = TypeList<nullptr_t>;
    };

    void Do_IBase() { printf("\n Doing IBase"); }

};

class ISine:public IBase {

public:

    struct I_T_TypeInfo {

        using I_T_BaseList = TypeList<IBase>;
    };
};


class IBox:public IBase {
public:

    struct I_T_TypeInfo {

        using I_T_BaseList = TypeList<IBase>;
    };

};

class Alpha:public IBox, public ISine {
public:

    struct I_T_TypeInfo {

        using I_T_BaseList = TypeList<IBox, ISine>;
    };

};

class Bulk :public Alpha {};
class Gold :public Alpha {};
class Bliz :public Gold {};
class Null{};








template <class T_CastFrom, class T_CastTo, class T_CurrBase = auto, _Uint32t iFromBaseCounter = 0, _Uint32t iCurrBaseCounter = 0, _Uint32t iterCounter = 0>
constexpr T_CastTo* XCast_WalkPolyTree(T_CastFrom* pCastFromObj, T_CastTo* pCastToObj = nullptr)
{

    using T_FromBaseList = typename T_CastFrom::I_T_TypeInfo::I_T_BaseList;


    if constexpr(iterCounter <= 0)
    {

        using T_CurrBase_ = typename W_TypMgr::TypeAt<iFromBaseCounter, T_FromBaseList>::Type;

        if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase_>)
        {
            //there is path to T_CastTo, follow this path

            if constexpr (std::is_convertible_v<T_CurrBase_, T_CastTo>)
            {
                pCastToObj = pCastFromObj;

            }//if constexpr (std::is_convertible_v<T_CurrBase, T_CastTo>)
            else
            {
                using T_CurrBaseList = typename T_CurrBase_::I_T_TypeInfo::I_T_BaseList;
                using T_NextBase = typename W_TypMgr::TypeAt < iCurrBaseCounter, T_NextBaseList>::Type;

                //nullptr_t means we are at a class with no base, end of the line
                if constexpr(not std::is_same_v<T_NextBase, nullptr_t>)
                {
                    pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iFromBaseCounter, iCurrBaseCounter, (iterCounter + 1) >(pCastFromObj);
                }
                else
                {
                    constexpr uint32_t iNextBaseIdx = iCurrBaseCounter + 1;

                    if constexpr(iNextBaseIdx < T_CurrBaseList::size)
                    {
                        //there is still more base classes in this path so up basecounter and keep checking
                        using T_NextBase = typename W_TypMgr::TypeAt<iNextBaseIdx, T_CurrBaseList>::Type;
                        pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iFromBaseCounter, iNextBaseIdx, (iterCounter + 1) >(pCastFromObj);
                    }

                    constexpr uint32_t iNextFromBaseIdx = iFromBaseCounter + 1;

                    if constexpr((pCastToObj == nullptr) && (iNextFromBaseIdx < T_FromBaseList::size))
                    {
                        //still more base clases up counter keep checking
                        using T_NextBase = typename W_TypMgr::TypeAt< iNextFromBaseIdx, T_FromBaseList>::Type;
                        pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iNextFromBaseIdx, 0, (iterCounter + 1) >(pCastFromObj);
                    }

                }//else if constexpr(not std::is_same_v<T_NextBase_, nullptr_t>)

            }//else  if constexpr (std::is_convertible_v<T_CurrBase, T_CastTo>)


        }//if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase>)
        else
        {//no path to T_CastTo so up the basecounter and try next base in thelist

            const uint32_t iNextBaseIndex = (iFromBaseCounter + 1);

            if constexpr(iNextBaseIndex < T_FromBaseList::size)
            {
                using T_NextBase = typename W_TypMgr::TypeAt < iNextBaseIndex, T_FromBaseList>::Type;

                pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iNextBaseIndex, 0 (iterCounter + 1) >(pCastFromObj);

            }//if constexpr(iNextBaseIndex < T_FromBaseList::size)
            else
            {
                //end of base class list
            }//else  if constexpr(iNextBaseIndex < T_FromBaseList::size)

        }//else  if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase>)


    }//if constexpr(iterCounter <= 0)
    else
    {

        static_assert(not std::is_same_v<T_CurrBase, nullptr_t>);

        if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase>)
        {

            if constexpr (std::is_convertible_v<T_CurrBase, T_CastTo>)
            {
                pCastToObj = pCastFromObj;

            }//if constexpr (std::is_convertible_v<T_CurrBase, T_CastTo>)
            else
            {
                //using T_CurrBaseList = typename T_CurrBase::I_T_TypeInfo::I_T_BaseList;
                //using T_CurrBaseInfo = typename T_CurrBase::I_T_TypeInfo;
                //using T_CurrBaseList = typename T_CurrBaseInfo::I_T_BaseList;

                using T_NextBase = typename W_TypMgr::TypeAt<iCurrBaseCounter, T_CurrBaseList>::Type;

                //nullptr_t means we are at a class with no base, end of the line
                if constexpr(not std::is_same_v<T_NextBase, nullptr_t>)
                {
                    pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iFromBaseCounter, iCurrBaseCounter, (iterCounter + 1) >(pCastFromObj);
                }
                else
                {

                    if constexpr((iCurrBaseCounter + 1) < T_CurrBaseList::size)
                    {
                        //there is still more base classes in this path so up basecounter and keep checking
                        using T_NextBase = typename W_TypMgr::TypeAt<(iCurrBaseCounter + 1), T_CurrBaseList>::Type;
                        pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, iFromBaseCounter, (iCurrBaseCounter + 1), (iterCounter + 1) >(pCastFromObj);
                    }

                    if constexpr((pCastToObj == nullptr) && ((iFromBaseCounter + 1) < T_FromBaseList::size))
                    {
                        //still more base clases up counter keep checking
                        using T_NextBase = typename W_TypMgr::TypeAt< (iFromBaseCounter + 1), T_FromBaseList>::Type;
                        pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, (iFromBaseCounter + 1), 0, (iterCounter + 1) >(pCastFromObj);
                    }


                }//else if constexpr(not std::is_same_v<T_NextBase_, nullptr_t>)

            }//else //if constexpr (std::is_convertible_v<T_CurrBase, T_CastTo>)

        }//if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase>)
        else
        {
            using T_CurrBaseList = typename T_CurrBase::I_T_TypeInfo::I_T_BaseList;
            if constexpr((iCurrBaseCounter + 1) < T_CurrBaseList::size)
            {
                //there is still more base classes in this path so up basecounter and keep checking
                using T_NextBase_ = typename W_TypMgr::TypeAt<(iCurrBaseCounter + 1), T_CurrBaseList>::Type;
                pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase_, iFromBaseCounter, (iCurrBaseCounter + 1), (iterCounter + 1) >(pCastFromObj);
            }

            if constexpr((pCastToObj == nullptr) && ((iFromBaseCounter + 1) < T_FromBaseList::size))
            {
                //still more base clases up counter keep checking
                using T_NextBase = typename W_TypMgr::TypeAt< (iFromBaseCounter + 1), T_FromBaseList>::Type;
                pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo, T_NextBase, (iFromBaseCounter + 1), 0, (iterCounter + 1) >(pCastFromObj);
            }


        }//else if constexpr(std::is_base_of_v<T_CastTo, T_CurrBase>)




    }//else if constexpr(iterCounter <= 0)


    return pCastToObj;
}


template <class T_CastFrom, class T_CastTo>
constexpr T_CastTo* XCast(T_CastFrom* pCastFromObj, T_CastTo* pCastToObj = nullptr)
{


    if constexpr(std::is_base_of_v<T_CastTo, T_CastFrom>)
    {

        if constexpr (std::is_convertible_v<T_CastFrom, T_CastTo>)
        {
            pCastToObj = pCastFromObj;
        }
        else
        {
            //using T_FromBaseList = typename T_CastFrom::I_T_TypeInfo::I_T_BaseList;
            pCastToObj = XCast_WalkPolyTree<T_CastFrom, T_CastTo>(pCastFromObj);


        }//else if constexpr (std::is_convertible_v<T_CastFrom, T_CastTo>)

    }//if constexpr(std::is_base_of_v<T_CastTo, T_CastFrom>)
    else
    {
        //return null user neeed to ensure thier is path

    }//else //if constexpr(std::is_base_of_v<T_CastTo, T_CastFrom>)

    return pCastToObj;
}

Спасибо

0 ответов

Другие вопросы по тегам