Использование std::apply с вариативными пакетами

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

Что я пробовал до сих пор, так это следующее:

#include <tuple>
struct Base{
    virtual void base_function() = 0;
};

template<typename ...T>
struct A : public Base{
    std::tuple<T...> as;
    A(T... pack):as(pack...){};
    void base_function(){
        std::apply([](auto t){t.base_function();}, as);
    }
};

struct B : public Base{
    void base_function(){};
};


struct C : public Base{
    void base_function(){};
};

struct D : A<B, C>{
    D():A(B(),C()){};
};

Я ожидал, что apply будет вызываться для base_function из классов B и C при вызове base_function для D. Но компилятор выдает следующую ошибку:

error: no matching function for call to
'__invoke(A<T>::base_function() [with T = {B, C}]::<lambda(auto:1)>, std::__tuple_element_t<0, std::tuple<B, C> >&, std::__tuple_element_t<1, std::tuple<B, C> >&)'

Просто чтобы вы знали, классы Base и D (и любое наследование от Base) не нужны для минимального примера. Ваша проблема проявляется так же (и решение @ Jarod42 работает так же) даже без них.

Spencer 11.02.2019 16:13

@Spencer Удаление класса D не вызывает ошибку, потому что компилятор не генерирует никакого кода без объявления версии A. Базовый класс был там, когда код сокращался, и он должен дать некоторый контекст.

sqrtroot 12.02.2019 18:51

Но вы могли бы просто объявить A<B,C> везде, где объявили объект D.

Spencer 12.02.2019 23:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
3
1 116
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

std::apply не делает того, что вы думаете. Это для передачи кортежа параметров в функцию (тип Callable). Другими словами, в самом кортеже нет функции base_function. см. https://en.cppreference.com/w/cpp/utility/apply

Я бы интерпретировал замешательство OP как мысль, что apply берет унарную функцию и применяет ее к каждому элементу в кортеже по очереди, а не как применение унарной функции непосредственно к кортежу (что было бы бессмысленно, поскольку вы могли бы просто... сделать это уже).

Barry 11.02.2019 16:41
Ответ принят как подходящий

Первый параметр std::apply должен быть функтором с той же арностью, что и количество элементов кортежа, поэтому в вашем случае вариативность:

template <typename ...Ts>
struct A : public Base{
    std::tuple<Ts...> as;
    A(Ts... pack) : as(pack...){}

    void base_function(){
        std::apply([](auto&... ts){(ts.base_function(), ...);}, as);
    }
};

Никогда не видел синтаксиса, используемого в лямбде, не могли бы вы объяснить немного больше, что он на самом деле делает. Как компилятор узнает, что делать с пакетом параметров ts?

sqrtroot 11.02.2019 14:38

Посмотрите на складное выражение.

Jarod42 11.02.2019 14:40

Это здорово, но вы можете добавить объяснение, почему std::apply не работает так, как думал OP.

Spencer 11.02.2019 16:06

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