访问并调用 std::function 的变体

Visit and invoke a variant of std::function

本文关键字:function 访问 调用 std      更新时间:2023-10-16

我正在使用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;
}

std::visit要求变体中的每个类型都有一个有效的"操作"。如果func有一个std::function<void(int)>而不是像现在这样std::function<void(void)>,那么就没有办法对它采取行动。由于这(可以(取决于运行时,std::visit必须在编译时检查变体的每个可能的替代项都可用于调用可调用。

例如,您可以将 lambda 合并在一起,或者为变体中的每个类型设置一个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);

这是另一个示例,根据 cpp 首选项页面改编到您的情况:

#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);
}
}