TypeCast.h
#include <iostream>
using namespace std;
#pragma region TypeList
template<typename... T>
struct TypeList;
template<typename T, typename U>
struct TypeList<T, U>
{
using Head = T;
using Tail = U;
};
template<typename T, typename... U>
struct TypeList<T, U...>
{
using Head = T;
using Tail = TypeList<U...>;
};
#pragma endregion
#pragma region Length
template<typename... T>
struct Length;
template<>
struct Length<TypeList<>>
{
enum { value = 0};
};
template<typename T, typename... U>
struct Length<TypeList<T, U...>>
{
enum { value = 1 + Length< TypeList<U...>>::value };
};
#pragma endregion
#pragma region TypeAt
/*
TypeAt< TypeList<Tail...>, index - 1 >::Result 가 타입을 의미 하는지
값을 의미 하는지 컴파일러는 알지 못 함.
때문에 이런 모호함 때문에 템플릿 인자에 의존적인 이름은 기본적으로 '타입'
이 아닌 '값'으로 컴파일러가 처리하게 되는데,
'타입'을 명시 하려면 typename 붙여 줘야 한다.
*/
template<typename TL, int index>
struct TypeAt;
template<typename Head, typename... Tail>
struct TypeAt<TypeList<Head, Tail...>, 0>
{
using Result = Head;
};
template<typename Head, typename... Tail, int index>
struct TypeAt<TypeList<Head, Tail...>, index>
{
using Result = typename TypeAt<TypeList<Tail...>, index - 1>::Result;
};
#pragma endregion
#pragma region IndexOf
template <typename TL, typename T>
struct IndexOf;
template <typename... Tail, typename T>
struct IndexOf<TypeList<T, Tail...>, T>
{
enum { value = 0 };
};
template <typename T>
struct IndexOf<TypeList<>, T>
{
enum { value = -1 };
};
template <typename Head, typename... Tail, typename T>
struct IndexOf<TypeList<Head, Tail...>, T>
{
private:
enum { temp = IndexOf<TypeList<Tail...>, T>::value };
public:
enum { value = (temp == -1) ? -1 : temp + 1 };
};
#pragma endregion
#pragma region Conversion
template<typename From, typename To>
class Conversion
{
private:
using Small = __int8;
using Big = __int16;
/// ... 매개변수 우선순위가 낮음.
static Small Test(const To&) { return 0; }
static Big Test(...) { return 0; }
static From MakeFrom() { return 0; }
public:
enum { exists = ( sizeof(Test(MakeFrom())) == sizeof(Small) ) };
};
#pragma endregion
#pragma region TypeCast
template<typename TL>
class TypeConversionBefore
{
public:
enum
{
length = Length<TL>::value
};
// 런타임에 정해지는 변수와 컴파일에 정해지는 값이 혼용되어 컴파일 불가능.
TypeConversionBefore()
{
for (int i = 0; i < length; i++;)
{
for (int j = 0; j < length; j++;)
{
using FromType = typename TypeAt<TL, i>::Result;
using ToType = typename TypeAt<TL, j>::Result;
if (Conversion<const FromType*, const ToType*>::exists)
s_convert[i][j] = true;
else
s_convert[i][j] = false;
}
}
}
};
// v 값 별로 별도의 클래스
template<int v>
struct Int2Type
{
enum { value = v};
};
template<typename TL>
class TypeConversion
{
public:
enum
{
length = Length<TL>::value
};
TypeConversion()
{
MakeTable(Int2Type<0>(), Int2Type<0>());
}
template<int i, int j>
static void MakeTable(Int2Type<i>, Int2Type<j>)
{
using FromType = typename TypeAt<TL, i>::Result;
using ToType = typename TypeAt<TL, j>::Result;
if (Conversion<const FromType, const ToType>::exists)
{
s_convert[i][j] = true;
}
else
{
s_convert[i][j] = false;
}
MakeTable(Int2Type<i>(), Int2Type<j + 1>());
}
template<int i>
static void MakeTable(Int2Type<i>, Int2Type<length>)
{
MakeTable(Int2Type<i + 1>(), Int2Type<0>());
}
template<int j>
static void MakeTable(Int2Type<length>, Int2Type<j>)
{
}
static bool CanConvert(int from, int to)
{
static TypeConversion conversion;
return s_convert[from][to];
}
public:
static bool s_convert[length][length];
};
// s_convert는 멤버 변수 같지만 전역 변수 이기 때문에 클래스 외부에 전역 변수 선언 하듯 선언 해야 한다.
// 다만 해당 클래스 네임스페이스를 이용해서만 접근 가능 하도록 변수를 선언한다.
template<typename TL>
bool TypeConversion<TL>::s_convert[length][length];
#pragma endregion
TypeCast.cpp
#include "TypeCast.h"
class Player
{
};
class Knight : public Player
{
};
class Mage : public Player
{
};
class Archer : public Player
{
};
int main()
{
// TypeList
{
TypeList<Knight>::Head;
TypeList<Knight>::Tail;
TypeList<Knight, Mage>::Head;
TypeList<Knight, Mage>::Tail;
TypeList<Knight, Mage, Archer>::Head;
TypeList<Knight, Mage, Archer>::Tail::Head;
TypeList<Knight, Mage, Archer>::Tail::Tail;
}
// Length
{
Length<TypeList<Knight>>().value;
Length<TypeList<Knight, Mage>>().value;
Length<TypeList<Knight, Mage, Archer>>().value;
}
// TypeAt
{
using TL = TypeList<Knight, Mage, Archer>;
TypeAt<TL, 0>::Result;
TypeAt<TL, 1>::Result;
TypeAt<TL, 2>::Result;
}
// IndexOf
{
using TL = TypeList<Knight, Mage, Archer>;
IndexOf<TL, Knight>().value;
IndexOf<TL, Mage>().value;
IndexOf<TL, Archer>().value;
}
// Conversion
{
Conversion<Knight, Player>().exists;
Conversion<Player, Knight>().exists;
Conversion<Mage, Knight>().exists;
}
// TypeCast
{
using TL = TypeList<Player, Mage, Archer>;
bool can1 = TypeConversion<TL>().CanConvert(1, 1);
bool can2 = TypeConversion<TL>().CanConvert(0, 2);
bool can3 = TypeConversion<TL>().CanConvert(2, 0);
}
}
'Programming Language > C++' 카테고리의 다른 글
#define vs typedef (0) | 2022.02.22 |
---|---|
[인강/코드없는 프로그래밍] easy way (0) | 2022.02.21 |
[인강/코드없는 프로그래밍] 병렬 프로그래밍을 필요한 이유 (0) | 2022.02.21 |
[인강/코드없는 프로그래밍] false sharing (0) | 2022.02.20 |
CustomAllocator] 5단계_StompAllocator_2 (0) | 2022.02.19 |