当前位置: 首页 > news >正文

2511C++,CTAD简化回调

原文

是否可用CTAD来简化WRL回调函数的使用

Bwmat问,“CTAD能否避免在最后一例中需要冗长的类型名”,这是对显式特化相当冗长的类型的响应.

void MyClass::RegisterCompletion(ABI::IAsyncAction* action)
{m_showingToken = inputPane->put_Showing(Microsoft::WRL::Callback<ABI::ITypedEventHandler<//<<ABI::InputPane*,ABI::InputPaneVisibilityEventArgs*>>(//>>this, &MyClass::OnInputPaneShowing).Get());
}

现在,不能在此真正使用CTAD(推导类模板参数),因为回调不是一个类.
类模板参数推导,是为了改进类命名中,缺少推导类型.但是函数确实有推导类型!所以来使用它.
从此开始:

template<typename TDelegateInterface,typename TCallbackObject,typename... TArgs
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

想推导TDelegateInterfaceTypedEventHandler<TArgs...>:

template<typename TDelegateInterface= TypedEventHandler<TArgs...>,//..typename TCallbackObject,typename... TArgs
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

可惜,这不管用,因为模板默认参数不能引用未来的模板参数.
试重排参数.

template<typename TCallbackObject,//<<typename... TArgs,typename TDelegateInterface= TypedEventHandler<TArgs...>//>>
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

但是,这不管用,因为模板参数包必须在模板参数列表的尾.

可按专门有两个TArg一个其他情况分割模板.

template<typename TDelegateInterface,//<<typename TCallbackObject,typename... TArgs,//>>
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);
template<typename TCallbackObject,//<<typename TArg1, typename TArg2,typename TDelegateInterface =TypedEventHandler<TArg1, TArg2>//>>
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

可惜,因为调用歧义,这失败了.当回调的参数数量恰好是两个时,必须删除第一个.

template<typename TDelegateInterface,typename TCallbackObject,typename... TArgs,
>
std::enable_if_t<sizeof...(TArgs) != 2,//..ComPtr<TDelegateInterface>>
Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);
template<typename TCallbackObject,typename TArg1, typename TArg2,typename TDelegateInterface =TypedEventHandler<TArg1, TArg2>
>
ComPtr<TDelegateInterface> Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

但即使使用该版本,双参回调很挫:如果想指定一个自定义闭包接口(比如,比如SuspendingEventHandler),你必须费力地完成前三个参数,这样才能最终指定最后参数.

Callback<MyObject, IInspectable*, SuspendingEventArgs*, SuspendingEventHandler>(//..this, &MyObject::OnSuspending);

相反可用未来的类型推导.

template<typename TDelegateInterface = void,//..typename TCallbackObject,typename... TArgs
>
ComPtr<std::conditional_t<std::is_same_v<TDelegateInterface, void>,TypedEventHandler<TArgs...>,TDelegateInterface>>
Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

但是等等,TypedEventHandler只接受两个模板参数,因此如果使用仅接受一个参数成员函数指针调用回调,会收到编译器错误,因为它无法构建TypedEventHandler<TArg>.

struct MyObject
{HRESULT OnUIInvoked(IUICommand* command);
};
Callback<UICommandInvokedHandler<(this, &MyObject::OnUIInvoked);
//^^^错误:`模板参数`推导/替换失败,`TypedEventHandler`的`模板参数`数量错误

必须延迟提及TypedEventHandler<TArgs...>,直到开始使用它.

template<typename... TArgs>//<<
struct TypedEventHandlerHolder
{using type = TypedEventHandler<TArgs...>;
};//>>template<typename TDelegateInterface = void,typename TCallbackObject,typename... TArgs
>
ComPtr<typename std::conditional_t<std::is_same_v<TDelegateInterface, void>,TypedEventHandlerHolder<TArgs...>,//..std::type_identity<TDelegateInterface>>::type//..
>
Callback(_In_ TCallbackObject *object,_In_ HRESULT (TCallbackObject::* method)(TArgs...)
);

现在,回到顶部,我提到CTAD不适用,因为CTAD针对类模板,但回调是一个函数模板.
但是,如果把回调变成类模板呢?

template<typename TDelegateInterface,typename TCallbackObject,//..typename... TArgs
>
struct Callback : ComPtr<TDelegateInterface>
{Callback(TCallbackObject *object,HRESULT (TCallbackObject::* method)(TArgs...));
};

现在,CTAD将推导TCallbackObjectTArgs,可用推导指南来推导TDelegateInterface.

template<typename TCallbackObject,typename TArg1, TArg2
>
Callback(TCallbackObject*,HRESULT (TCallbackObject::*)(TArg1, TArg2))-> Callback<TypedEventHandler<TArg1, TArg2>, TCallbackObject, TArg1, TArg2>;

可惜,CTAD不适合部分特化,因此无法如下:

Callback<SuspendingEventHandler>(this, &MyObject::OnSuspending);

所以我想,被困在从未来推导类型重载函数中.
但实际上,制胜之举是不上场.

与其试使回调优雅,不如创建单独的TypedEventHandlerCallback函数.

template<typename TCallbackObject,typename TArg1, typename TArg2>
ComPtr<TypedEventHandler<TArg1, TArg2>>TypedEventHandlerCallback(TCallbackObject* object,HRESULT (TCallbackObject::*method)(TArg1, TArg2));

原始代码将是

void MyClass::RegisterCompletion(ABI::IAsyncAction* action)
{m_showingToken = inputPane->put_Showing(TypedEventCallback(this, &MyClass::OnInputPaneShowing).Get());
}

此时,还可创建个EventHandlerCallback函数.

template<typename TCallbackObject,typename TArg>
ComPtr<EventHandler<TArg>>
EventHandlerCallback(TCallbackObject* object,HRESULT (TCallbackObject::*method)(IInspectable*, TArg));
http://www.dtcms.com/a/617797.html

相关文章:

  • 【ros2】ROS2 C++参数设置指南(含跨节点修改方法)
  • STM32通信接口----USART
  • 解决Web游戏Canvas内容在服务器部署时的显示问题
  • 我爱学算法之—— 哈希
  • Linux字符设备驱动模型
  • C++ List 容器详解:迭代器失效、排序与高效操作
  • 婚纱网站wordpress微商模板
  • GPT问答:泛型、哈希表与缓存、命名参数。251116
  • 免费学软件的自学网站保健品网站建设流程
  • 网络访问流程:HTTPS + TCP + IP
  • 智能体AI、技术浪潮与冲浪哲学
  • 基于 PyTorch + BERT 意图识别与模型微调
  • 沃尔沃公司网站建设微信官方网站建设
  • 网站备案域名怎么买找在农村适合的代加工
  • 42 解决一些问题
  • Claude Code 功能+技巧
  • 基于人脸识别和 MySQL 的考勤管理系统实现
  • AUTOSAR_CP_OS-Operating System for Multi-Core:多核操作系统
  • 什么是 “信任模型” 和 “安全假设”?
  • 【秣厉科技】LabVIEW工具包——HIKRobot(海康机器人系列)
  • 网易UU远程全功能技术解构:游戏级性能突围与安全边界探析
  • 蓝桥杯第八届省赛单片机设计完全入门(零基础保姆级教程)
  • 搭建网站分类建立名词
  • 没有域名的网站wordpress占用资源
  • RPA+AI双剑合璧!小红书商品笔记自动发布,效率提升2000%[特殊字符]
  • 19.传输层协议UDP
  • linux服务-rsync+inotify文件同步-rsync
  • 机器学习之ravel()的作用
  • Wi-Fi 7路由器性能分析:从传输速率到多设备协同全面解析
  • 【Java手搓RAGFlow】-1- 环境准备