Метафункция для выполнения операции приведения к статическим полиморфным типам 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;
}
Спасибо