поиск и удаление типа из tuple
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.05.18 11:53
Оценка: 5 (1)
привет!

собственно сабж. наверняка кто-то писал нечто подобное, — поделитесь плиз
т.е. нужно понимать, присутствует ли какой-то конкретный тип в тьюпле, и если присутствует — в какой позиции. ну и удаление по позиции.

спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: поиск и удаление типа из tuple
От: night beast СССР  
Дата: 25.05.18 12:05
Оценка: +1
Здравствуйте, niXman, Вы писали:

X>собственно сабж. наверняка кто-то писал нечто подобное, — поделитесь плиз

X>т.е. нужно понимать, присутствует ли какой-то конкретный тип в тьюпле, и если присутствует — в какой позиции. ну и удаление по позиции.

X>спасибо.


Буст используется?
Глянь boost::mpl (mpl::find, mpl::remove)
Re[2]: поиск и удаление типа из tuple
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.05.18 12:10
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Буст используется?

аа, нет. с бустом и я могу =)

сорри, забыл указать.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: поиск и удаление типа из tuple
От: vopl Россия  
Дата: 25.05.18 12:34
Оценка: 23 (2) +2
Здравствуйте, niXman, Вы писали:

X>привет!


X>собственно сабж. наверняка кто-то писал нечто подобное, — поделитесь плиз

X>т.е. нужно понимать, присутствует ли какой-то конкретный тип в тьюпле, и если присутствует — в какой позиции. ну и удаление по позиции.

X>спасибо.


#include <tuple>
#include <type_traits>
#include <cassert>

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
// если присутствует — в какой позиции
template <class T>
constexpr std::size_t pos(std::tuple<> * = nullptr)
{
    return 0;
}

template <class T, class Head, class... Tail>
constexpr std::size_t pos(std::tuple<Head, Tail...> * = nullptr)
{
    if constexpr(std::is_same_v<T, Head>)
    {
        return 0;
    }

    return pos<T, Tail...>()+1;
}

template <class T, class... Args>
constexpr std::size_t pos(const std::tuple<Args...> &)
{
    return pos<T, Args...>();
}

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
// присутствует ли какой-то конкретный тип в тьюпле
template <class T, class... Args>
constexpr bool present(std::tuple<Args...> * v = nullptr)
{
    return sizeof...(Args) > pos<T, Args...>();
}

template <class T, class... Args>
constexpr bool present(const std::tuple<Args...> &)
{
    return present<T, Args...>();
}

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
// ну и удаление по позиции
template <std::size_t I, class... Args>
constexpr bool del(const std::tuple<Args...> &v)
{
    return std::tuple_cat(left<I>(v), right<I+1>(v));//left, right - домашка, смотри тут http://rsdn.org/forum/cpp.applied/7087910
}

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
int main()
{
    std::tuple<int, char, float> t;
    static_assert(0 == pos<int>(t));
    static_assert(1 == pos<char>(t));

    static_assert(true == present<int>(t));
    static_assert(true == present<char>(t));
    static_assert(false == present<short>(t));

    static_assert(std::is_same_v<std::tuple<char, float>, decltype(del<0>(t)));
    static_assert(std::is_same_v<std::tuple<int, float>, decltype(del<1>(t)));

    assert(std::make_tuple(220, '2', 0.5) == del<2>(std::make_tuple(220, '2', 0.5f, 0.5)));

    return 0;
}
Re: поиск и удаление типа из tuple
От: rg45 СССР  
Дата: 06.06.18 11:24
Оценка:
Здравствуйте, niXman, Вы писали:

X>привет!

X>собственно сабж. наверняка кто-то писал нечто подобное, — поделитесь плиз
X>т.е. нужно понимать, присутствует ли какой-то конкретный тип в тьюпле, и если присутствует — в какой позиции. ну и удаление по позиции.

Я бы делал как-то так:

https://ideone.com/ORCJeo

template <typename T, typename From, typename = From, typename = std::index_sequence<>>
struct RemoveFromHelper;

template <typename T, typename...E, typename Head, typename...Tail, size_t...I>
struct RemoveFromHelper<T, std::tuple<E...>, std::tuple<Head, Tail...>, std::index_sequence<I...>>
 : RemoveFromHelper<T, std::tuple<E...>, std::tuple<Tail...>, std::index_sequence<I..., sizeof...(E) - sizeof...(Tail) - 1>> {};

template <typename T, typename...E, typename...Tail, size_t...I>
struct RemoveFromHelper<T, std::tuple<E...>, std::tuple<T, Tail...>, std::index_sequence<I...>>
 : RemoveFromHelper<T, std::tuple<E...>, std::tuple<Tail...>, std::index_sequence<I...>> {};

template <typename T, typename...E, size_t...I>
struct RemoveFromHelper<T, std::tuple<E...>, std::tuple<>, std::index_sequence<I...>>
{
  using Input = std::tuple<E...>;
  using Output = std::tuple<std::tuple_element_t<I, Input>...>;

  Output operator()(const Input& input) const { return {std::get<I>(input)...}; }
  Output operator()(Input&& input) const { return {std::move(std::get<I>(input))...}; }
};

template <typename T, typename From>
using RemoveFromOutput = typename RemoveFromHelper<T, std::decay_t<From>>::Output; 

template <typename T, typename From>
RemoveFromOutput<T, From> remove_from(From&& t)
{
  return RemoveFromHelper<T, std::decay_t<From>>()(std::forward<From>(t));
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 06.06.2018 16:44 rg45 . Предыдущая версия . Еще …
Отредактировано 06.06.2018 11:52 rg45 . Предыдущая версия .
Отредактировано 06.06.2018 11:30 rg45 . Предыдущая версия .
Re[2]: поиск и удаление типа из tuple
От: vopl Россия  
Дата: 06.06.18 15:49
Оценка: 5 (1)
Здравствуйте, rg45, Вы писали:

R>Я бы делал как-то так:


R>https://ideone.com/hbLGBG


если доступен 17 стандарт — можно очень красиво сделать через constexpr-if + constexpr-lambda как предикат для выбора элементов

http://coliru.stacked-crooked.com/a/444ae2d492fe1140

#include <iostream>
#include <type_traits>
#include <tuple>

using namespace std;

// помогалка - формирование пачки индексов от 0 до Size-1, удовлетворяющих заданному предикату
template <size_t Size, class Pred, size_t idx=0, size_t... pass>
constexpr auto makeIndices(const Pred &pred)
{
    if constexpr(idx >= Size)
    {
        return index_sequence<pass...>();
    }
    else if constexpr(pred(integral_constant<size_t, idx>()))
    {
        return makeIndices<Size, Pred, idx+1, pass..., idx>(pred);
    }
    else
    {
        return makeIndices<Size, Pred, idx+1, pass...>(pred);
    }
}

// помогалка - вычленить элементы туплы для заданных индексов
template <class Tuple, size_t... I>
constexpr auto extract(Tuple&&v, index_sequence<I...> = index_sequence<I...>())
{
    return tuple<tuple_element_t<I, decay_t<Tuple>>...>(get<I>(forward<Tuple>(v))...);
}

// помогалка - вычленить элементы туплы, индексы которых удовлетворяют предикату
template <class Tuple, class Pred>
constexpr auto extract(Tuple&&v, const Pred &pred)
{
    return extract(std::forward<Tuple>(v), makeIndices<tuple_size_v<decay_t<Tuple>>>(pred));
}

// помогалки закончились, теперь использование: вырезать из туплы все элементы заданного типа
template <class Target, class Tuple>
constexpr auto del(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return !is_same_v<Target, tuple_element_t<idx(), decay_t<Tuple>>>;
    });
}

// вырезать по индексу
template <size_t I, class Tuple>
constexpr auto del(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return idx() != I;
    });
}

// от начала и до заданного размера
template <size_t Size, class Tuple>
constexpr auto left(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return idx() < Size;
    });
}

// от заданного индекса и до конца
template <size_t I, class Tuple>
constexpr auto rightFrom(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return idx() >= I;
    });
}

// на заданный размер от конца
template <size_t Size, class Tuple>
constexpr auto right(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return idx() >= tuple_size_v<decay_t<Tuple>> - Size;
    });
}

// от заданного индекса, заданной длины
template <size_t I, size_t Size, class Tuple>
constexpr auto mid(Tuple &&v)
{
    return extract(std::forward<Tuple>(v), [](auto idx)
    {
        return idx() >= I && idx() < I+Size;
    });
}

template <class Tuple>
void print(const Tuple& t)
{
    cout<<"[";

    apply([](const auto &... v)
    {
        size_t cnt = 0;
        ((cout<<(cnt++ ? ", " : "")<<v),...);
    }, t);

    cout<<"]"<<endl;
}

int main()
{
    auto src = make_tuple("one", 1, "two", 2, "three", 3, "fourty", 40);
    print(src);

    print(del<int>(src));
    print(del<2>(src));
    print(left<2>(src));
    print(right<2>(src));
    print(rightFrom<2>(src));
    print(mid<2, 3>(src));
    print(mid<2, 0>(src));
}
Re[2]: поиск и удаление типа из tuple
От: AeroSun  
Дата: 08.06.18 13:48
Оценка:
А можно получить описание как оно работает — что за чем вызывается и почему именно так?
Re[3]: поиск и удаление типа из tuple
От: vopl Россия  
Дата: 08.06.18 14:48
Оценка:
Здравствуйте, AeroSun, Вы писали:

AS>А можно получить описание как оно работает — что за чем вызывается


это лучше в дебагере самому посмотреть, вполне наглядно получается. Можно пощелкать по стеку интерактивно, туда-сюда покрутить

  код
#include <iostream>
#include <tuple>
#include <type_traits>
#include <cassert>

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
// если присутствует — в какой позиции
template <class T>
constexpr std::size_t posImpl()
{
    return 0;
}

template <class T, class Head, class... Tail>
constexpr std::size_t posImpl()
{
    if constexpr(std::is_same_v<T, Head>)
    {
        return 0;
    }

    return posImpl<T, Tail...>()+1;
}

template <class T, class... Args>
constexpr std::size_t pos(const std::tuple<Args...> &)
{
    return posImpl<T, Args...>();
}

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
int main()
{
    std::tuple<int, char, float> t;
    std::cout << pos<char>(t) << std::endl;
    std::cout << pos<double>(t) << std::endl;

    return 0;
}


Re[3]: поиск и удаление типа из tuple
От: AeroSun  
Дата: 10.06.18 22:14
Оценка:
Можно объяснить как работает makeIndices? Пошаговая отладка ничего не прояснила.
Re[4]: поиск и удаление типа из tuple
От: vopl Россия  
Дата: 11.06.18 12:27
Оценка:
Здравствуйте, AeroSun, Вы писали:

AS>Можно объяснить как работает makeIndices? Пошаговая отладка ничего не прояснила.


#include <type_traits>
#include <utility>
#include <iostream>

using namespace std;

// формирование пачки индексов от 0 до Size-1, удовлетворяющих заданному предикату
/*
 *  шаблонная функция makeIndices параметризуется следующим:
 *  1. size_t Size - количество генерируемых индексов без учета предиката
 *  2. class Pred - тип предиката, в нашем случае это будет лямбда с constexpr operator(),
 *      способным принимать любую конкретную инстанцию std::integral_constant и возвращающую буль-результат
 *  3. size_t idx - текущий индекс при рекурсии, он будет подвергаться проверкам и в случае успеха будет
 *      включен в результирующий набор индексов
 *  4. size_t... pass - результирующий набор индексов, накапливается по мере рекурсии
 *
 * начальное значение параметра Size надо задавать явно
 * Pred, idx, pass - выводятся автоматически,
 * Pred - по переданному в функцию аргументу,
 * idx по дефолтному значению становится нулем,
 * pass остается пустым
 *
 * работает рекурсивно, на каждой итерации проверяет индекс по предикату и накапливает его в pass, останов рекурсии
 * по превышению Size
 *
 * в результате работы получится объект типа integer_sequence<size_t, pass...>, на обратном ходе рекурсии он
 * будет без изменений возвращяться выше
 *
 * https://en.cppreference.com/w/cpp/types/integral_constant
 * https://en.cppreference.com/w/cpp/utility/integer_sequence
 *
 * в нагрузку - тут можно по лекции посмотреть
 * https://www.youtube.com/results?search_query=c%2B%2B+%D0%BC%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
 */
template <size_t Size, class Pred, size_t idx=0, size_t... pass>
auto makeIndices(const Pred &pred)
{
    //проверка на выход текущего индекса idx за границу Size
    if constexpr(idx >= Size)
    {
        //если вышел - формируется результат в виде инстанции std::integer_sequence, заряженную накопленными индексами в pass
        return integer_sequence<size_t, pass...>();
    }
    //иначе - делается вызов предиката, которому передается текущий рабочий индекс для проверки
    else if constexpr(pred(integral_constant<size_t, idx>()))
    {
        //если предикат вернул истину - делается следующая рекурсивная итерация для
        //текущего индекса равного idx+1 и pass равного <pass..., I>, то есть текущий индекс добавляется к pass
        return makeIndices<Size, Pred, idx+1, pass..., idx>(pred);
    }
    //иначе - делается следующая рекурсивная итерация для idx+1 и pass без измененй, то есть текущий индекс игнорируется
    else
    {
        return makeIndices<Size, Pred, idx+1, pass...>(pred);
    }
}

template <size_t... I>
void print(index_sequence<I...>)
{
    cout<<"[";

    size_t cnt = 0;
    ((cout<<(cnt++ ? ", " : "")<<I),...);

    cout<<"]"<<endl;
}

int main()
{
    //предикат для нечетных чисел
    auto oddPred = [](auto idx)
    {
        return !!(idx()%2);
    };

    //предикат для четных чисел
    auto evenPred = [](auto idx)
    {
        return !(idx()%2);
    };

    print(makeIndices<10>(oddPred));
    print(makeIndices<10>(evenPred));

    return 0;
}
Re[5]: поиск и удаление типа из tuple
От: AeroSun  
Дата: 12.06.18 14:01
Оценка:
Спасибо! Затупил просто, что pass может быть и пустой. Пытался понять что и каким образом там передаётся и как потом засунутые туда данные оттуда вырезаются без лишнего.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.