template <int Ind,class T>
struct IndType
{
};
template <class ... TT>
struct TypeList
{
template <int Ind,class T>
TypeList<TT...,IndType<(sizeof ... (TT))+Ind,T> > operator + (IndType<Ind,T>) { return {}; }
};
template <class ... TT>
using IndList = decltype( ( TypeList<>{} + ... + IndType<1,TT>{} ) ) ;
// IntList<T1,T2,T3> == TypeList<IndType<1,T1>,IndType<2,T2>,IndType<3,T3> >
Здравствуйте, uzhas, Вы писали:
К>>А вообще, тут прямо напрашивается сделать по-теоркатовски. Аппликативные функторы и стрелки.
U>цель ZipWith([1..], types, indexed_type) ?
Ну, что-то типа того.
К>>Но эмулировать всю полноту их — дело тугое.
U>без этого тухло, нужны полноценные списки типов, сильно буксуем иначе
С одной стороны, возможности для этого есть (как показал лисп с nil и (.), — "если у вас есть фломастер, можно изрисовать всё на свете, кроме фломастера; если у вас есть два фломастера — можно изрисовать вообще всё")
С другой стороны, нужно что-то делать с гетерогенностью:
— вариадики — красиво, компактно, но очень ограничено
— рекурсивные типы — универсально, но громоздко
— объединить вариадики и рекурсивные типы — нужны переходники, что добавляет громоздкости
Так-то можно помыслить следующее:
// кортеж на вариадике
template<class... Xs> struct type_tuple {};
// делаем MAP
template<template<class>class M, class... Xs> using map_var_to_tuple = make_tuple<M<Xs>...>;
// а вот так делается переходник из цельного кортежа на вариадик
// (можно ли сделать паттерн-матчинг как-то более красиво, без специализации шаблона и зависимых имён?)
template<template<class>class M, class T> struct map_tuple_to_tuple_impl;
template<template<class>class M, class...Xs> struct map_tuple_to_tuple_impl<M,type_tuple<Xs...>> { using result = map_var_to_tuple<M,Xs...>; };
template<template<class>class M, class T> using map_tuple_to_tuple = typename map_tuple_to_tuple_impl<M,T>::result;
template<class X> struct box {};
template<class X> X unbox(box<X>); // будет использоваться в паре с declspec, поэтому тело не нужно
template<template<class,class>class F, class Y> struct funbox {};
template<class X, template<class,class>class F, class Y>
box<F<X,Y>> operator + (box<X>, funbox<F,Y>) { return {} };
// делаем REDUCE
template<template<class,class>class F, class X0, class... Xs> using foldl_var = declspec(unbox((box<X0>() + ... + funbox<F,Xs>())));
Вот у нас уже есть два фломастера, рисуем!
template<int I, class X> struct indexed {};
template<class T, class Y> struct add_indexed_impl;
template<class... IXs, class Y> struct add_indexed_impl<type_tuple<IXs...>, Y> { result = type_tuple<IXs..., indexed<sizeof...(IXs),Y>>; };
template<class T, class Y> using add_indexed = typename add_indexed_impl<T,Y>::result;
Тут прямо напрашивается сделать несколько вариантов частичного применения функций — не только лишь тупой карринг.
Хотя свёртка списка (x0, x1, x2, ...) двуместной функцией f(_,_) может быть представлена как рекуррентный забег по списку одноместных функций f(_,x1), f(_,x2), ... со стартовым значением x0.
Но мы же не Йот на С++ пишем, а что-то с оглядкой на практическое использование...
Здравствуйте, Шахтер, Вы писали:
Ш>
Ш>template <int Ind,class T>
Ш>struct IndType
Ш> {
Ш> };
Ш>template <class ... TT>
Ш>struct TypeList
Ш> {
Ш> template <int Ind,class T>
Ш> TypeList<TT...,IndType<(sizeof ... (TT))+Ind,T> > operator + (IndType<Ind,T>) { return {}; }
Ш> };
Ш>template <class ... TT>
Ш>using IndList = decltype( ( TypeList<>{} + ... + IndType<1,TT>{} ) ) ;
Ш>// IntList<T1,T2,T3> == TypeList<IndType<1,T1>,IndType<2,T2>,IndType<3,T3> >
Ш>
Приём, конечно, интересный, но какой-то не полный. Есть два вопроса:
— как получить индекс типа?
— как записать тип по индексу?
Здравствуйте, B0FEE664, Вы писали:
BFE>Приём, конечно, интересный, но какой-то не полный.
Погоди, тема только начинает раскрываться.
BFE>Есть два вопроса:
BFE>- как получить индекс типа?
У типа нет индекса -- они могут совпадать.
BFE>- как записать тип по индексу?
В следующий раз...
Здравствуйте, Шахтер, Вы писали:
Ш>
Ш>template <int Ind,class T>
Ш>struct IndType
Ш> {
Ш> };
Ш>template <class ... TT>
Ш>struct TypeList
Ш> {
Ш> template <int Ind,class T>
Ш> TypeList<TT...,IndType<(sizeof ... (TT))+Ind,T> > operator + (IndType<Ind,T>) { return {}; }
Ш> };
Ш>template <class ... TT>
Ш>using IndList = decltype( ( TypeList<>{} + ... + IndType<1,TT>{} ) ) ;
Ш>// IntList<T1,T2,T3> == TypeList<IndType<1,T1>,IndType<2,T2>,IndType<3,T3> >
Ш>
Идеологически неловко — поднимать тип T в IndType<1,T>, только для того, чтобы потом этот индекс 1 тут же отбросить.
Либо мы должны честно прибавлять Ind к последнему индексу, захардкодить автоинкремент.
Я бы предпочёл так
template<class T> struct type {};
template<int I, class T> struct indexed_type {};
template<class... ITs> struct indexed_types {};
template<class... ITs, class T>
auto operator + (indexed_types<ITs> its, type<T> t) -> indexed_types<ITs..., indexed_type<sizeof...(ITs)+1, T>
{ return {}; }
template<class... Ts>
using make_indexed = decltype( (indexed_types<>{} + ... + type<Ts>{}) )
А вообще, тут прямо напрашивается сделать по-теоркатовски. Аппликативные функторы и стрелки.
Но эмулировать всю полноту их — дело тугое.