如何定义严格检查参数类型的Concept区分DualHandler与SingleHandler
解决方案
要区分DualHandler和SingleHandler,核心是检测是否存在专门针对Derived&的handle重载,而非仅通过隐式转换兼容Derived&的Base&版本。以下是实现方式:
#include <type_traits> struct Base {}; struct Derived : public Base {}; struct DualHandler { static void handle(Base&) {} static void handle(Derived&) {} }; struct SingleHandler { static void handle(Base&) {} }; // 包装Derived,禁止向Base&的隐式转换 struct DerivedNoBaseConv : Derived { operator Base&() = delete; }; // 辅助模板:检测是否存在接受Derived&(或其子类引用)的handle重载 template<typename T> struct HasExactDerivedHandle { private: // 若T能处理DerivedNoBaseConv&,说明存在针对Derived&的重载(因为无法转Base&) template<typename U> static auto test(int) -> decltype(U::handle(std::declval<DerivedNoBaseConv&>()), std::true_type{}); // 匹配失败时的兜底 template<typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(0))::value; }; // 最终的Concept template<typename T> concept IsDualHandler = // 必须能处理Base& requires(Base& b) { T::handle(b); } && // 必须存在专门处理Derived&的重载 HasExactDerivedHandle<T>::value; // 测试验证 static_assert(IsDualHandler<DualHandler>); static_assert(!IsDualHandler<SingleHandler>);
原理说明
DerivedNoBaseConv继承自Derived,但删除了向Base&的转换运算符,阻断了通过隐式转换调用handle(Base&)的路径。HasExactDerivedHandle利用SFINAE特性:如果T有handle(Derived&)重载,那么DerivedNoBaseConv&可以隐式转换为Derived&,调用会成功,返回std::true_type;如果T只有handle(Base&),则调用会因无法转换而失败,返回std::false_type。IsDualHandler组合了两个条件:能处理Base&,且存在专门处理Derived&的重载,完美区分DualHandler和SingleHandler。
内容的提问来源于stack exchange,提问作者dshin
相关产品推荐
相关产品推荐

