728x90

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);

    }
}

 

728x90

+ Recent posts