Посетите и вызовите вариант std :: function - PullRequest
0 голосов
/ 23 мая 2018

Я использую std::variant для хранения различных подписей std::function с.Указанные функции хранятся в векторе, причем последние извлекаются из карты.

Как вызвать каждую функцию в векторе std::variant?Я чувствую, что должен использовать std::visit, но я не могу понять правильное использование.

#include <variant>
#include <functional>
#include <map>
#include <iostream>
#include <functional>

using var_t = std::variant<std::function<void(void)>, std::function<void(int)>>;
enum class EventEnum { A, B, C };

struct Controller {
    template<EventEnum E>
    void subscribe(var_t fn) {
        auto& callbacksVec = callbacks.at(E);
        callbacksVec.push_back(fn);
    }

    template<EventEnum E>
    void notify() {
        auto& callbacksVec = callbacks.at(E);
        for (auto& func : callbacksVec) {
            // std::visit([](auto& arg){ std::invoke(arg); }, func);
        }
    }

    std::map<EventEnum, std::vector<var_t>> callbacks;
};

int main() {
    auto fn = []() { std::cout << "lambda callback" << std::endl; };
    Controller myController;
    myController.subscribe<EventEnum::A>(fn);
    myController.notify<EventEnum::A>();

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вот еще один пример, адаптированный со страницы cppreference к вашей ситуации:

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
#include <functional>

 using var_t = std::variant<std::function<void(void)>, std::function<void(int)>>;

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main() {
    std::vector<var_t> vec = {
        []() {std::cout << "void" << std::endl;},
        [](int arg) {std::cout << "int " << arg << std::endl;}
    };

    for (auto& v: vec) {
        std::visit(overloaded {
            [](const std::function<void(void)>& fv) { fv(); },
            [](const std::function<void(int)>& fi) { fi(42); }
        }, v);
    }
}
0 голосов
/ 23 мая 2018

std::visit требует, чтобы у каждого типа внутри варианта было допустимое «действие».Если бы func имел бы std::function<void(int)> вместо std::function<void(void)>, как это происходит сейчас, тогда не было бы никакого способа воздействовать на него.И поскольку это (can) зависит от времени выполнения, std::visit должен проверить во время компиляции, что каждая возможная альтернатива варианта может использоваться для вызова вашего вызываемого объекта.

Например, вы можете объединить лямбды вместе, илииметь if constexpr каскад для каждого типа в варианте.

template<typename ...Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<typename ...Ts> overloaded(Ts...) -> overloaded<Ts...>;

std::visit(overloaded{
    [](const std::function<void(void)> &Void) { std::invoke(Void); },
    [](const std::function<void(int)> &Int) { std::invoke(Int, 1); }}, func);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...