如何判断类是否继承自指定模板基类并分支执行逻辑
解决方法:自定义类型检测Trait + constexpr if
嘿,这个问题的核心是要检测一个类型是否继承自任意实例化版本的模板基类(比如A<S>不管S是什么),标准库的std::is_base_of没法直接搞定——因为它需要明确指定具体的基类类型,而我们这里的基类是模板实例化出来的任意类型。
我们可以借助SFINAE(Substitution Failure Is Not An Error)技巧,自定义两个类型检测trait,再结合C++17的constexpr if来实现需求。
第一步:定义检测继承关系的Trait
我们先写两个辅助的类型检测结构体,用来判断某个类型是否继承自任意版本的A或B:
#include <type_traits> #include <iostream> template <typename T> class A { /* ... */ }; template <typename T> class B { /* ... */ }; // 检测是否继承自任意A<S>的辅助Trait template <typename T> struct is_derived_from_A_impl { // 当T可以隐式转换为A<S>时,匹配这个重载,返回true_type template <typename S> static std::true_type test(const A<S>&); // 其他情况匹配这个重载,返回false_type static std::false_type test(...); // 推导test函数调用的结果类型 using type = decltype(test(std::declval<T>())); }; // 封装成constexpr变量,方便直接使用 template <typename T> constexpr bool is_derived_from_A = is_derived_from_A_impl<T>::type::value; // 同理,检测是否继承自任意B<S>的Trait template <typename T> struct is_derived_from_B_impl { template <typename S> static std::true_type test(const B<S>&); static std::false_type test(...); using type = decltype(test(std::declval<T>())); }; template <typename T> constexpr bool is_derived_from_B = is_derived_from_B_impl<T>::type::value;
第二步:补全foo函数的判断条件
在C++17及以上,我们可以用constexpr if来在编译时选择执行哪个分支,这样不会因为分支代码无法编译而出错:
template <typename T> void foo(const T& object) { if constexpr (is_derived_from_A<T>) { std::cout << "object has type A\n"; } if constexpr (is_derived_from_B<T>) { std::cout << "object has type B\n"; } }
测试示例
为了验证效果,我们可以写几个测试类:
// 测试类:继承自A<int> class DerivedA : public A<int> {}; // 测试类:继承自B<std::string> class DerivedB : public B<std::string> {}; // 测试类:不继承自A或B class Unrelated {}; int main() { DerivedA a; DerivedB b; Unrelated u; foo(a); // 输出:object has type A foo(b); // 输出:object has type B foo(u); // 无输出 return 0; }
兼容C++11/14的方案
如果你的项目还在使用C11或C14,没法用constexpr if,可以通过函数重载+SFINAE来实现不同版本的foo:
// 处理继承自A的情况 template <typename T, typename = std::enable_if_t<is_derived_from_A<T>>> void foo(const T& object) { std::cout << "object has type A\n"; } // 处理继承自B的情况 template <typename T, typename = std::enable_if_t<is_derived_from_B<T> && !is_derived_from_A<T>>> void foo(const T& object) { std::cout << "object has type B\n"; } // 处理既不继承自A也不继承自B的情况(可选) template <typename T, typename = std::enable_if_t<!is_derived_from_A<T> && !is_derived_from_B<T>>> void foo(const T& object) { // 无操作或其他逻辑 }
这种方式会在编译时根据T的类型匹配对应的重载,同样能达到需求。
内容的提问来源于stack exchange,提问作者Andreas T
相关产品推荐
相关产品推荐

