Created
February 6, 2018 08:15
-
-
Save langthom/30c75e65f23bf5e7a75aa32e34bfce55 to your computer and use it in GitHub Desktop.
Playing around with meta-functions, understanding placeholders as they are defined in boost.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Playing around with meta-functions, placeholders and stuff. Thomas Lang, 2018. | |
#include <iostream> | |
#include <typeinfo> | |
namespace placeholder_helper { | |
// Helper utility for finding the N'th argument in a template parameter pack. | |
template<int Current, int N, typename FirstArg, typename... Args> | |
struct find_arg { | |
static_assert(Current < N, "Invalid argument position!"); | |
typedef typename find_arg<Current + 1, N, Args...>::type type; | |
}; | |
template<int N, typename WantedArg, typename... Args> | |
struct find_arg<N, N, WantedArg, Args...> { | |
typedef WantedArg type; | |
}; | |
} // placeholder_helper | |
template<int N> | |
struct int_ { | |
static constexpr int value = N; | |
}; | |
namespace type_list { | |
struct NIL { | |
typedef NIL Head; | |
typedef NIL Tail; | |
}; | |
template<typename H, typename T = NIL> | |
struct type_list { | |
typedef H Head; | |
typedef T Tail; | |
}; | |
template<int FirstNum, int... Nums> | |
struct make_integral_list { | |
typedef type_list<int_<FirstNum>, typename make_integral_list<Nums...>::type> type; | |
}; | |
template<int Num> | |
struct make_integral_list<Num> { | |
typedef type_list<int_<Num>, NIL> type; | |
}; | |
// foldl :: (a -> b -> a) -> a -> [b] -> a | |
// foldl _ a [] = a | |
// foldl f a xs = foldl f (f a (head xs)) (tail xs) | |
template<typename Function, typename Acc, typename List> | |
struct foldl { | |
typedef typename Function::template apply<Acc, typename List::Head>::value NewAcc; | |
typedef typename foldl<Function, NewAcc, typename List::Tail>::type type; | |
}; | |
template<typename Function, typename Acc> | |
struct foldl<Function, Acc, NIL> { | |
typedef Acc type; | |
}; | |
} // type_list | |
// Representation of an argument i.e. an argument type. | |
template<int N> | |
struct arg { | |
template<typename... Args> | |
struct apply { | |
typedef typename placeholder_helper::find_arg<0, N, Args...>::type type; | |
}; | |
}; | |
// Typedef two wildcards, sufficient for our testing purposes. | |
typedef arg<0> _0; | |
typedef arg<1> _1; | |
// Example function: plus_f<int_<X>, int_<Y>> -> int_<X+y> | |
struct plus_f { | |
template<typename X, typename Y> | |
struct apply { | |
typedef int_<X::value + Y::value> value; | |
}; | |
}; | |
// ----------------------------------------------------------------------------- | |
template<typename X, typename Y> // X, Y are placeholders. | |
struct minus_f_ph { | |
template<typename X1, typename Y1> // X1, Y1 are the real types. | |
struct apply { | |
// First, choose the arguments based on the order given through the placeholders. | |
typedef typename X::template apply<X1, Y1>::type first_arg; | |
typedef typename Y::template apply<X1, Y1>::type second_arg; | |
// Then, do the computation on the choosen arguments. | |
typedef int_<first_arg::value - second_arg::value> value; | |
}; | |
}; | |
int main(void) { | |
// Test 1: check if selected type is right. | |
typedef typename arg<1>::template apply<char, short, int>::type ResultType; | |
std::cout << "result type: " << typeid(ResultType).name() << std::endl; | |
// Test 2: foldl (+) 1 [1..3] == 7 ? | |
typedef type_list::make_integral_list<1, 2, 3>::type onetwothree; | |
typedef type_list::foldl<plus_f, int_<1>, onetwothree>::type result; | |
static_assert(result::value == 7, "foldl (+) 1 [1..3] expected to be 7"); | |
std::cout << "foldl (+) 1 [1..3] = " << result::value << std::endl; | |
// Test 3: placeholder fold. (Note switched arguments) | |
typedef type_list::foldl<minus_f_ph<_0, _1>, int_<1>, onetwothree>::type result2_1; | |
static_assert(result2_1::value == -5, "foldl (\\x y -> x-y) 1 [1..3] expected to be -5"); | |
std::cout << "foldl (\\x y -> x-y) 1 [1..3] = " << result2_1::value << std::endl; | |
typedef type_list::foldl<minus_f_ph<_1, _0>, int_<1>, onetwothree>::type result2_2; | |
static_assert(result2_2::value == 1, "foldl (\\x y -> y-x) 1 [1..3] expected to be 1"); | |
std::cout << "foldl (\\x y -> y-x) 1 [1..3] = " << result2_2::value << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment