- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
所以我正在创建一种事件处理程序,如果您愿意的话,我正在编写一个“事件监听器包装器”。
基本思路是这样的:当您想要订阅一个事件时,您可以创建一个函数,该函数应在事件触发时调用。 <-- 已经完成了(有点,我会解释)
您将此监听器函数放入包装器中,以将函数传递给调度程序。
调度程序获取一个事件,为您的监听器找到包装器,并使用事件设置的参数值调用底层函数。
只要所有听众只接受我的 EventBase
类的一个参数,我就已经有了一些工作。然后我必须将其强制转换为传递监听器的正确事件。
我想要的是让我的监听器函数具有“任何”类型的参数,并以一种允许我根据触发的事件用我想要的任何参数调用它的方式存储函数。每个监听器函数只会接收一种类型的事件,或者事件本身。这将使我不必在每个监听器中对每个事件进行类型转换,而是传递正确的事件。
我为这个包装器找到了一些几乎完美的代码,但有一些我似乎无法修复的小问题。我将在下面解释。
@hmjd 的代码:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
void myFunc1(int arg1, float arg2)
{
std::cout << arg1 << ", " << arg2 << '\n';
}
void myFunc2(const char *arg1)
{
std::cout << arg1 << '\n';
}
class DelayedCaller
{
public:
template <typename TFunction, typename... TArgs>
static std::unique_ptr<DelayedCaller> setup(TFunction&& a_func,
TArgs&&... a_args)
{
return std::unique_ptr<DelayedCaller>(new DelayedCaller(
std::bind(std::forward<TFunction>(a_func),
std::forward<TArgs>(a_args)...)));
}
void call() const { func_(); }
private:
using func_type = std::function<void()>;
DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
func_type func_;
};
int main()
{
auto caller1(DelayedCaller::setup(&myFunc1, 123, 45.6));
auto caller2(DelayedCaller::setup(&myFunc2, "A string"));
caller1->call();
caller2->call();
return 0;
}
我在这里做的第一件事是必须将 std::unique_ptr
替换为 std::shared_ptr
。不知道为什么真的。这几乎有效。在我的用例中,我需要存储一个方法函数(意味着绑定(bind)需要传递包含方法对象?),并且在存储函数时我不知道参数值是什么,这就是事件来决定。所以我的调整如下:
class DelayedCaller
{
public:
template <typename TFunction, typename TClass>
static std::shared_ptr<DelayedCaller> setup(TFunction&& a_func,
TClass && a_class)
{
auto func = std::bind(std::forward<TFunction>(a_func),
std::forward<TClass>(a_class),
std::placeholders::_1);
return std::shared_ptr<DelayedCaller>(new DelayedCaller(func));
}
template <typename T>
void call( T v ) const { func_(v); }
private:
using func_type = std::function<void( )>;
DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
func_type func_;
};
为了测试,我删除了参数包并将其替换为持有函数的类对象的直接参数。我还为绑定(bind)提供了一个用于 1 个参数的占位符(最好稍后用 void call()
函数替换)。
它是这样创建的:
eventManager->subscribe(EventDemo::descriptor, DelayedCaller::setup(
&AppBaseLogic::getValueBasic,
this
));
问题是:在这条线上:
return std::shared_ptr<DelayedCaller>(new DelayedCaller(func));
我得到“没有匹配函数来调用‘DelayedCaller::DelayedCaller(std::_Bind(AppBaseLogic*, std::_Placeholder<1>)>&)’ 返回 std::shared_ptr(new DelayedCaller(func));"
只有在使用 placeholder::_1
时才会发生这种情况。如果我用正确类型的已知值替换它,它就可以工作,当然,当然在没有任何有用数据的情况下调用该函数除外。
所以,我想我需要一种方法来存储带有我不知道其类型的占位符的函数?
如果我把事物的名称弄错了,请原谅我。我是 c++ 的新手,我最近几天才开始学习它。
**编辑:**
好的,所以我只是更新为什么我需要这样存储函数。我的事件调度程序中有一张 map ,如下所示:
std::map< const char*, std::vector<DelayedCaller> > _observers;
我希望能够像这样调用“Delayed Caller”中的函数:
void Dispatcher::post( const EventBase& event ) const
{
// Side Note: I had to do this instead of map.find() and map.at() because
// passing a "const char*" was not evaluating as equal to event.type() even
// though event.type() is also a const char*. So instead I am checking it
// myself, which is fine because it gives me a little more control.
std::string type(event.type());
for( auto const &x : _observers ) {
std::string type2(x.first);
if ( type == type2 ) {
auto&& observers = x.second;
for( auto&& observer : observers ) {
// event may be any descendant of EventBase.
observer.slot->call(event);
}
break;
}
}
}
我的听众目前看起来像这样:
void AppBaseLogic::getValue(const EventBase &e) {
const EventDemo& demoEvent = static_cast<const EventDemo&>( e );
std::cout << demoEvent.type();
}
我正在尝试存储每个函数,以便参数看起来像这样:
void AppBaseLogic::getValue(const EventAnyDescendant &e) {
std::cout << e.type();
}
希望对您有所帮助。感谢大家花时间帮助我解决这个问题。
关于 lambda 的旁注:有人建议使用它们,我知道它们是什么或如何使用它们,但我打算对它们进行一些研究,看看这是否更有意义。从我所看到的情况来看,我担心他们的可维护性。
最佳答案
不太清楚您的DelayedCaller
正在做什么。如果您重构代码并删除它,您将得到:
auto c1 = []() {myFunc1(123, 45.6);}; // or use bind, the result is exactly the same
auto c2 = []() {myFunc2("A string");};
vector<function<void()>> v {c1, c2};
v[0]();
v[1](); // ok
现在,如果您尝试在这个版本中引入占位符修改,那么为什么它首先不起作用就变得很清楚了:
auto cSome = [](???) {getValueBasic(???)};
您将 ???
替换为什么?
getValueBasic
接受一些特定类型的参数,它会泄漏到 cSome
签名中。无论您将其包装在多少个模板包装器中,它都会泄漏到每个包装器的签名中,直至并包括最外层的包装器。 bind
和 std::placeholders
不是能够让它不发生的魔杖。
换句话说,如果您不知道函数的类型,就无法调用它(很明显,不是吗?)
一种类型删除签名并使所有可调用对象符契约(Contract)一类型的方法是在运行时对其进行类型检查和类型转换(又名dynamic_cast
)。另一种是双重 dispatch 。这两种方法都是 visitor 相同一般概念的不同体现。谷歌“访问者模式”了解更多信息。
关于c++ - 将具有任意参数和占位符的函数存储在类中并稍后调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47030645/
我正在运行一个辅助角色,并检查 Azure 上托管的存储中是否存在数据。当我将连接字符串用于经典类型的存储时,我的代码可以正常工作,但是当我连接到 V2 Azure 存储时,它会抛出此异常。 “远程服
在我的应用程序的主页上,我正在进行 AJAX 调用以获取应用程序各个部分所需的大量数据。该调用如下所示: var url = "/Taxonomy/GetTaxonomyList/" $.getJSO
大家好,我正在尝试将我的商店导入我的 Vuex Route-Gard。 路由器/auth-guard.js import {store} from '../store' export default
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我的 Windows 计算机上的本地文件夹中有一些图像。我想将所有图像上传到同一容器中的同一 blob。 我知道如何使用 Azure Storage SDKs 上传单个文件BlockBlobServi
我尝试发出 GET 请求来获取我的 Azure Blob 存储帐户的帐户详细信息,但每次都显示身份验证失败。谁能判断形成的 header 或签名字符串是否正确或是否存在其他问题? 代码如下: cons
这是用于编写 JSON 的 NeutralinoJS 存储 API。是否可以更新 JSON 文件(推送数据),而不仅仅是用新的 JS 对象覆盖数据。怎么做到的??? // Javascript
我有一个并行阶段设置,想知道是否可以在嵌套阶段之前运行脚本,所以像这样: stage('E2E-PR-CYPRESS') { when { allOf {
我想从命令行而不是从GUI列出VirtualBox VM的详细信息。我对存储细节特别感兴趣。 当我在GUI中单击VM时,可以看到包括存储部分在内的详细信息: 但是到目前为止,我还没有找到通过命令行执行
我有大约 3500 个防洪设施,我想将它们表示为一个网络来确定流动路径(本质上是一个有向图)。我目前正在使用 SqlServer 和 CTE 来递归检查所有节点及其上游组件,只要上游路径没有 fork
谁能告诉我 jquery data() 在哪里存储数据以及何时删除以及如何删除? 如果我用它来存储ajax调用结果,会有性能问题吗? 例如: $("body").data("test", { myDa
有人可以建议如何为 Firebase 存储中的文件设置备份。我能够备份数据库,但不确定如何为 firebase 存储中的文件(我有图像)设置定期备份。 最佳答案 如何进行 Firebase 存储的本地
我最近开始使用 firebase 存储和 firebase 功能。现在我一直在开发从功能到存储的文件上传。 我已经让它工作了(上传完成并且文件出现在存储部分),但是,图像永远保持这样(永远在右侧加载)
我想只允许用户将文件上传到他们自己的存储桶中,最大文件大小为 1MB,仍然允许他们删除文件。我添加了以下内容: match /myusers/{userId}/{allPaths=**} { al
使用生命周期管理策略将容器的内容从冷访问层移动到存档。我正在尝试以下策略,希望它能在一天后将该容器中的所有文件移动到存档层,但事实并非如此在职的。我设置了选择标准“一天未使用后”。 这是 json 代
对于连接到 Azure 存储端点,有 http 和 https 两个选项。 第一。 https 会带来开销,可能是 5%-10%,但我不支付同一个数据中心的费用。 第二。 http 更快,但 Auth
有人可以帮我理解这一点吗?我创建了Virtual Machine in Azure running Windows Server 2012 。我注意到 Azure 自动创建了一个存储帐户。当我进入该存
我是一名优秀的程序员,十分优秀!