Создание кортежа ссылок из другого кортежа по условию

У меня есть шаблонная структура ContainerInner, содержащая кортеж с векторами типов из вариативного шаблона, и структура Container, содержащая кортеж ContainerInner, указанный в ее шаблоне. Код выглядит следующим образом:

template<typename... Args>
struct ContainerInner
{
    std::tuple<std::vector<Args>...> m_elements;

    template<typename T>
    static constexpr bool containsOne()
    {
        return (std::is_same_v<T, Args> || ...);
    }

    template<typename... T>
    static constexpr bool contains()
    {
        return (containsOne<T>() && ...);
    }

    template<typename T>
    std::vector<T> &get()
    {
        return std::get<std::vector<T>>(m_elements);
    }
};

template<typename... T>
struct ArgList {
    template<typename... TTS>
    using add = ArgList<T..., ContainerInner<TTS...>>;
};
    
template<typename ListArgs>
struct Container;

template<typename... Args>
struct Container<ArgList<Args...>>
{
    std::tuple<Args...> m_containers;

    // It also crashes with std::tuple<Args&...> return type
    template<typename... T>
    inline auto getTuples()
    {
        auto tpl = std::make_tuple<Args&...>(std::get<Args>(m_containers)...);
        return tpl;
    }

    template<typename... T>
    ContainerInner<T...> &get()
    {
        return std::get<ContainerInner<T...>>(m_containers);
    }
};

using MyArgList = ArgList<>
    ::add<char, int>
    ::add<char, float>
    ::add<char, int, float>;

int main(int argc, char* args[])
{    
    Container <MyArgList> cnt;

    auto arr = cnt.getTuples<float>();

    std::get<ContainedType<char, int>>(arr).get<int>().push_back(3);

    std::cout << typeid(arr).name() << std::endl;
    std::cout << cnt.get<char, int>().get<int>().size() << std::endl;
}

Я хочу изменить метод getTuples так, чтобы он возвращал кортеж со ссылками на все ContainerInner из m_containers, содержащие указанные типы, что является условием, обрабатываемым статическим методом contains. Я подумал, что могу использовать такую ​​концепцию:

template<typename InnerCnt, typename T>
concept ContainedType = 
    requires(T a, InnerCnt b) {
       b.contains<T>();
    };

чтобы рекурсивно перебрать шаблон с переменным числом вариантов и использовать std::tuple_cat для построения окончательного массива, но не понял, как это сделать. Как я могу решить эту проблему?

РЕДАКТИРОВАТЬ. Я решил это, но, вероятно, не оптимальным способом. Я добавил обертку Query поверх перегруженного кортежа operator+ и использовал ее для разворачивания:

    template<typename... Args>
struct Query
{
    std::tuple<Args...> m_tpl;

    template<typename... TT>
    constexpr inline auto operator+(const Query<TT...> &rhs_)
    {
        return Query<Args..., TT...>(std::tuple_cat(m_tpl, rhs_.m_tpl));
    }

    template<typename... TT>
    constexpr inline auto &get()
    {
        return std::get<ContainerInner<TT...>&>(m_tpl);
    }
};

template<typename LST, typename CONTAINER_INNER>
constexpr inline auto getQueryElem(CONTAINER_INNER &t_)
{
    return Query<>();
}

template<typename LST, typename CONTAINER_INNER> requires Contained<CONTAINER_INNER, LST>
constexpr inline auto getQueryElem(CONTAINER_INNER &t_)
{
    return Query(std::tuple<CONTAINER_INNER&>(t_));
}


// Inside Container
template<typename... T>
constexpr inline auto getTuples()
{
    return (getQueryElem<Typelist<T...>>(std::get<Args>(m_containers)) + ...);
}

int main(int argc, char* args[]) {
  Container <MyArgList> cnt;
  auto arr = cnt.getTuples<int>();
  std::cout << typeid(arr).name() << std::endl;

  cnt.get<char, int>().get<int>().push_back(5);
  arr.get<char, int>().get<int>().push_back(-99);

  std::cout << cnt.get<char, int>().get<int>() << std::endl;
  std::cout << arr.get<char, int>().get<int>() << std::endl;
}

Кажется, это работает, но я не уверен, насколько хорошо компилятор это оптимизирует, на самом деле он может создавать временные запросы во время развертывания во время выполнения.

b.template contains<T>();?
Jarod42 19.07.2024 17:16

@Jarod42 Jarod42 Я уже это исправил, оно скомпилировалось в msvc, но не в gcc или clang.

SavedowW 19.07.2024 17:22

Можете ли вы предоставить работоспособный код (возможно, со ссылкой)? Так что мы можем экспериментировать. Мне непонятно, чего вы ожидаете от возвращения getTuples...

Jarod42 19.07.2024 18:13

@Jarod42 Конечно, вот ссылка . Этот код обращается к вектору напрямую и через возвращенную ссылку и проверяет, что это тот же вектор, а не копия. Он возвращает то, что ожидается, за вычетом форматирования имени типа gcc.

SavedowW 19.07.2024 18:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблемы от getTuples():

  • это шаблон, но он не использует его параметры. можно удалить.
  • std::make_tuple предназначен для вывода его параметра, который вы хотите std::tuple напрямую:
auto getTuples()
{
    auto tpl = std::tuple<Args&...>(std::get<Args>(m_containers)...);
    return tpl;
}

Демо

или используйте std::tie:

auto getTuples()
{
    return std::tie(std::get<Args>(m_containers)...);
}

Демо

Судя по вашему редактированию, вы хотите отфильтровать (во время компиляции) некоторые элементы кортежа, поэтому может помочь использование std::tuple_cat с функцией, которая возвращает пустой tuple или tuple с элементом:

template <typename... Ts, typename... Us>
auto filter(ContainerInner<Us...>& c)
{
    if constexpr (ContainerInner<Us...>::template contains<Ts...>()) {
        return std::tie(c);
    } else {
        return std::tuple<>{};
    }
}

А потом

template <typename... Ts>
constexpr auto getTuples()
{
    return std::tuple_cat(filter<Ts...>(std::get<Args>(m_containers))...);
})

Демо

Посмотрите на getTuples после редактирования, он использует свой параметр, я просто не знал, как его использовать в данный момент.

SavedowW 19.07.2024 17:32

Отредактировано, чтобы добавить ваш фильтр.

Jarod42 20.07.2024 18:09

Большое спасибо, я не знал, что вы можете сделать это с помощью 1 функции с помощью if constexpr здесь

SavedowW 21.07.2024 14:53

Альтернативой может быть перегрузка (с SFINAE или диспетчеризацией тегов).

Jarod42 21.07.2024 14:55

Другие вопросы по теме