Skip to content

Instantly share code, notes, and snippets.

@leafbird
Last active August 29, 2015 14:14
Show Gist options
  • Save leafbird/969d161c22c68dc78a59 to your computer and use it in GitHub Desktop.
Save leafbird/969d161c22c68dc78a59 to your computer and use it in GitHub Desktop.
Typelist: Implemented by variadic templates
#include "TypeList.h"
// from : https://functionalcpp.wordpress.com/2013/08/05/function-traits/
template<class F>
struct function_traits;
// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)> {
};
// member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&, Args...)>
{};
// const member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&, Args...)>
{};
// member object pointer
template<class C, class R>
struct function_traits<R(C::*)> : public function_traits<R(C&)>
{};
template<class R, class... Args>
struct function_traits<R(Args...)> {
using return_type = R;
using arg_types = TypeList::Types < Args... >;
static const size_t arity = TypeList::SizeOf<arg_types>::kValue;
template<size_t index>
struct argument {
using type = typename TypeList::TypeAt<arg_types, index>::Type;
};
};
#include "stdafx.h"
#include "TypeList.h"
struct TypeA { int value = 10; };
struct TypeB { int value = 20; };
struct TypeC { int value = 30; };
template<typename T>
struct Job {
static void Execute() {
std::cout << "sizeof(T) : " << sizeof(T) << std::endl;
}
};
void main() {
using list = TypeList::Types<TypeA, TypeB>;
std::cout << TypeList::SizeOf<list>::kValue<< std::endl;
static_assert(std::is_same<TypeList::HeadOf<list>::Type, TypeA>::value, "error");
static_assert(std::is_same<TypeList::TailOf<list>::Type, TypeB>::value, "error");
std::cout << TypeList::IndexOf<list, TypeA>::kValue << std::endl;
std::cout << TypeList::IndexOf<list, TypeB>::kValue << std::endl;
//std::cout << TypeList::IndexOf<list, float>::kValue << std::endl;
TypeList::NextOf<list, TypeA>::Type d = TypeB();
//TypeList::NextOf<list, char>::Type d = false;
std::cout << TypeList::IsElementOf<list, TypeB>::kValue << ", "
<< TypeList::IsElementOf<list, int>::kValue << std::endl;
using append_list = TypeList::Append < list, TypeC >::Type;
static_assert(TypeList::SizeOf<append_list>::kValue == 3, "error");
static_assert(TypeList::IndexOf<append_list, TypeA>::kValue == 0, "error");
static_assert(TypeList::IndexOf<append_list, TypeB>::kValue == 1, "error");
static_assert(TypeList::IndexOf<append_list, TypeC>::kValue == 2, "error");
static_assert(TypeList::IsElementOf<append_list, TypeC>::kValue, "error");
static_assert(!TypeList::IsElementOf<list, TypeC>::kValue, "error");
using removed_list = TypeList::Erase<append_list, TypeB>::Type;
static_assert(TypeList::SizeOf<removed_list>::kValue == 2, "error");
static_assert(std::is_same<TypeList::HeadOf<removed_list>::Type, TypeA>::value, "error");
static_assert(std::is_same<TypeList::TailOf<removed_list>::Type, TypeC>::value, "error");
using merge_list = TypeList::Append<append_list, removed_list>::Type;
static_assert(TypeList::SizeOf<merge_list>::kValue == 5, "error");
using test_types = TypeList::Types < int, short, char > ;
TypeList::Visitor<test_types, Job>::Execute();
}
namespace TypeList {
struct Null {};
template<typename ...T>
struct Types;
template<typename _Head>
struct Types < _Head > {
using Type = Types < _Head > ;
using Next = Null;
using Current = _Head;
};
template<typename _Head, typename ... _Tail>
struct Types < _Head, _Tail... > {
using Type = Types < _Head, _Tail... > ;
using Next = typename Types < _Tail... > ;
using Current = _Head;
};
template<typename _Types>
struct SizeOf {
static const size_t kValue = 1 + SizeOf<_Types::Next>::kValue;
};
template<>
struct SizeOf < Null > {
static const size_t kValue = 0U;
};
template<typename _Types>
struct HeadOf {
using Type = typename _Types::Current;
};
template<>
struct HeadOf < Null > {
using Type = Null;
};
template<typename _Types>
struct TailOf {
using Type = typename TailOf<typename _Types::Next>::Type;
};
template<typename _Tail>
struct TailOf < Types<_Tail> > {
using Type = _Tail;
};
template<typename _Types, size_t _index>
struct TypeAt {
using Type = typename TypeAt<typename _Types::Next, _index - 1>::Type;
};
template<typename _Types>
struct TypeAt < _Types, 0 > {
using Type = typename _Types::Current;
};
template<typename _Types, typename _Type>
struct IndexOf {
static_assert(SizeOf<typename _Types::Next>::kValue != 0, "No such types in typelist");
static const size_t kValue = typename IndexOf<typename _Types::Next, _Type>::kValue + 1U;
};
template<typename _Types>
struct IndexOf <_Types, typename _Types::Current> {
static const size_t kValue = 0U;
};
template<typename _Types, typename _Type>
struct NextOf {
using Type = typename NextOf<typename _Types::Next, _Type>::Type;
};
template<typename _Types>
struct NextOf < _Types, typename _Types::Current > {
using Type = typename HeadOf<typename _Types::Next>::Type;
};
template<typename _Types, typename _Type>
struct IsElementOf {
static const bool kValue = typename IsElementOf<typename _Types::Next, _Type>::kValue;
};
template<typename _Types>
struct IsElementOf < _Types, typename _Types::Current > {
static const bool kValue = true;
};
template<typename _Type>
struct IsElementOf < Null, _Type > {
static const bool kValue = false;
};
template<typename _Types, typename ..._Type>
struct Append;
template<typename ..._Type1, typename ..._Type2>
struct Append < Types<_Type1...>, _Type2...> {
using Type = typename Types<_Type1..., _Type2...>::Type;
};
template<typename ..._Type1, typename ..._Type2>
struct Append < Types<_Type1...>, Types<_Type2...>> {
using Type = typename Types<_Type1..., _Type2...>::Type;
};
template<typename _Types, typename ... _Type>
struct PushFront;
template<typename ..._Type1, typename ..._Type2>
struct PushFront < Types<_Type1...>, _Type2... > {
using Type = typename Types<_Type2..., _Type1...>::Type;
};
template<typename _Types, typename _Type>
struct Erase {
using Type = typename PushFront<typename Erase<typename _Types::Next, _Type>::Type,
typename _Types::Current>::Type;
};
template<typename _Types>
struct Erase < _Types, typename _Types::Current > {
using Type = typename _Types::Next;
};
template <typename _Types, template <class> class _Delegator>
struct Visitor {
static void Execute() {
_Delegator<typename _Types::Current>::Execute();
Visitor<typename _Types::Next, _Delegator>::Execute();
}
};
template <template <class> class _Delegator>
struct Visitor<Null, _Delegator> {
static void Execute() {}
};
} // namespace TypeList
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment