如何编写Concept检查含可变NTTP的模板类是否派生自同模板基类?
实现思路与可行方案
你的需求是可以实现的,核心思路是利用C++20的模板lambda或模板特化,结合派生类到基类的隐式转换来匹配Base<as...>的实例。
方案一:利用模板lambda的requires表达式
这是最简洁的实现方式,直接在Concept中通过尝试将目标类型转换为Base<as...>引用,触发模板参数推导:
#include <concepts> struct A { size_t x, y; }; template <A... as> class Base { public: Base() = delete; }; template <A... as> class Sub : Base<as...> {}; using foo = Sub<{1, 2}, {3, 4}>; // Concept to check if a type derives from Base template <typename T> concept DerivesFromBase = requires { // 尝试将T的临时对象转换为Base<as...>引用,推导as... []<A... as>(Base<as...> const&) {}((T const&){}); }; static_assert(DerivesFromBase<foo>, "foo must derive from Base"); static_assert(!DerivesFromBase<int>, "int should not derive from Base");
原理说明
当T是Base<as...>的派生类(比如Sub<as...>)时,(T const&){}可以隐式转换为Base<as...> const&,模板lambda的参数会成功推导出as...,整个requires表达式合法,Concept返回true。如果T与Base无关,转换会失败,Concept返回false。
方案二:模板特化结合类型特征
如果你需要更显式的类型匹配,可以通过辅助模板特化来实现:
#include <concepts> #include <type_traits> struct A { size_t x, y; }; template <A... as> class Base { public: Base() = delete; }; template <A... as> class Sub : Base<as...> {}; using foo = Sub<{1, 2}, {3, 4}>; // 辅助模板,默认匹配为false template <typename T> struct is_derived_from_base_impl : std::false_type {}; // 特化所有从Base<as...>派生的模板类 template <template <A...> typename Derived, A... as> requires std::derived_from<Derived<as...>, Base<as...>> struct is_derived_from_base_impl<Derived<as...>> : std::true_type {}; // 基于辅助模板定义Concept template <typename T> concept DerivesFromBase = is_derived_from_base_impl<T>::value; static_assert(DerivesFromBase<foo>, "foo must derive from Base"); static_assert(!DerivesFromBase<int>, "int should not derive from Base");
注意事项
- 两种方案都依赖C++20及以上的特性(Concept、模板lambda/模板特化约束)。
- 如果
Base的派生类不是通过相同的as...参数继承(比如template <A... as> class Sub : Base<{0,0}>),方案一仍会返回true(因为确实派生自某个Base实例),方案二则会返回false(因为Derived<as...>和Base<as...>的参数不匹配),可以根据你的实际需求选择。
内容的提问来源于stack exchange,提问作者Joshua Williams
相关产品推荐
相关产品推荐

