如何实现可识别Foo模板及其公有派生类的C++类型特征IsFoo
解决方案
你当前的IsFoo实现仅能匹配Foo模板的直接实例,无法识别派生类,以下两种实现都可以满足需求,优先推荐你用编译器已支持的concept版本,写法更简洁:
方案1:基于Concept实现(推荐)
#include <type_traits> template <class... T> struct Foo {}; // 定义concept:匹配任意Foo实例及其公有派生类 template <class T> concept IsFooConcept = requires(T val) { // 约束检查:val可以隐式转换为任意Foo实例的const引用,公有派生类天然满足该规则 []<typename... Args>(const Foo<Args>&) {}(val); }; // 兼容你原有代码中IsFoo<T>::value的调用形式 template <class T> struct IsFoo : std::bool_constant<IsFooConcept<T>> {}; // 可以直接在你的bar函数中使用,写法更简洁 template <class T> void bar (const T& t) { if constexpr (IsFooConcept<T>) // 按Foo类型处理 else // 通用处理逻辑 }
方案2:SFINAE实现(兼容无concept的C++17环境)
如果需要兼容不支持concept的场景,可以用传统SFINAE实现:
#include <type_traits> template <class... T> struct Foo {}; namespace detail { // 重载1:接收任意Foo实例的const指针,公有派生类指针可以隐式转换到该类型 template <typename... Args> std::true_type is_foo_impl(const Foo<Args...>*); // 重载2:兜底匹配所有不满足条件的类型 std::false_type is_foo_impl(...); } template <typename T> // 用std::decay_t剥离T的顶层cv、引用修饰,避免传入const T&这类类型识别失败 struct IsFoo : decltype(detail::is_foo_impl(std::declval<std::decay_t<T>*>())) {}; // C++17及以上可定义变量模板简化调用 template <typename T> constexpr bool IsFoo_v = IsFoo<T>::value;
验证用例
可以通过以下静态断言确认实现正确性:
struct Derived : public Foo<int, float> {}; struct NormalType {}; static_assert(IsFoo<Foo<int, float>>::value); // 直接Foo实例返回true static_assert(IsFoo<Derived>::value); // 公有派生类返回true static_assert(IsFoo<const Derived&>::value); // 带cv、引用修饰的派生类也能正确识别 static_assert(!IsFoo<NormalType>::value); // 非Foo派生类返回false
注意:两种实现都仅对公有继承自Foo的类型返回true,私有/保护继承的类型会正确返回false,符合你的需求。如果不需要识别带cv、引用修饰的类型,可以去掉
std::decay_t直接传入T*即可。
内容的提问来源于stack exchange,提问作者PluginPenguin
相关产品推荐
相关产品推荐

