Я сделал свой код немного похожим на списки в Haskell, потому что TMP - это чисто функциональный язык в C ++.
add_to_pack
эквивалентен конструктору списка Haskell (:)
. drop_from_end
реализовано как (в нотации Haskell) \x list -> take (length list - x) list
, где take n
просто берет первые n
элементы списка.
Полагаю, вы могли бы использовать std::tuple
напрямую вместо pack
, но мне больше понравилось это решение, потому что оно не использует кортеж как держатель пакета параметров шаблона. :)
Вот код:
#include <tuple>
#include <type_traits> // for std::conditional
template <typename... Pack>
struct pack
{ };
template <typename, typename>
struct add_to_pack;
template <typename A, typename... R>
struct add_to_pack<A, pack<R...>>
{
typedef pack<A, R...> type;
};
template <typename>
struct convert_to_tuple;
template <typename... A>
struct convert_to_tuple<pack<A...>>
{
typedef std::tuple<A...> type;
};
template <int, typename...>
struct take;
template <int N>
struct take<N>
{
typedef pack<> type;
};
template <int N, typename Head, typename... Tail>
struct take<N, Head, Tail...>
{
typedef
typename std::conditional<
(N > 0),
typename add_to_pack<
Head,
typename take<
N - 1,
Tail...
>::type
>::type,
pack<>
>::type type;
};
template <int N, typename... A>
struct drop_from_end
{
// Add these asserts if needed.
//static_assert(N >= 0,
// "Cannot drop negative number of elements!");
//static_assert(N <= static_cast<int>(sizeof...(A)),
// "Cannot drop more elements than size of pack!")
typedef
typename convert_to_tuple<
typename take<
static_cast<int>(sizeof...(A)) - N,
A...
>::type
>::type type;
};
int main()
{
drop_from_end<2, const char*, double, int, int>::type b{"pi", 3.1415};
}
А вот код на работе: через ideone.com .
Структура take
более или менее эквивалентна следующему коду Haskell:
take n [] = []
take n (x:xs)
| n > 0 = x : take (n - 1) xs
| otherwise = []