如何检查泛型成员函数签名?C++ MetaModifier编译期校验求助
编译期校验MetaModifier类型的实现方案
问题背景
已定义泛型结构体Meta:
template <size_t N> struct Meta { // ... };
需要实现MetaModifier用于编译期构建Meta类型,示例Modifier如下:
struct FooModifier { template <size_t N, size_t N2> Meta<N2> apply(Meta<N> meta) { // ... } };
现有apply_modifiers实现可正常运行,但需要校验Modifier类型,确保其拥有签名为Meta<N2> apply(Meta<N>)的方法,不匹配时给出友好编译提示:
template <typename Modifier, size_t N> static constexpr auto apply_modifier(Meta<N> meta, Modifier M) { return M.apply(meta); } template <size_t N, typename FirstModifier, typename... RestModifiers> static constexpr auto apply_modifiers(Meta<N> meta, FirstModifier F, RestModifiers... rest) { return apply_modifiers(apply_modifier(meta, F), rest...); } template <size_t N> static constexpr auto apply_modifiers(Meta<N> meta) { return meta; }
用户提出是否可以通过两步检查实现:先检查是否有apply方法,再检查返回类型是否为Meta类。
解决方案
方式一:使用C++20 Concept实现强校验
可以编写MetaModifier概念,直接约束Modifier的apply方法签名,代码简洁且符合现代C++风格:
#include <type_traits> // 辅助 trait:判断类型是否为Meta的实例 template <typename T> struct is_meta : std::false_type {}; template <size_t N> struct is_meta<Meta<N>> : std::true_type {}; template <typename T> constexpr bool is_meta_v = is_meta<T>::value; // 定义MetaModifier概念 template <typename Modifier> concept MetaModifier = requires(Modifier m, auto&& meta) { // 要求apply方法接受任意Meta<N>,且返回值是Meta类型 { m.apply(std::forward<decltype(meta)>(meta)) } -> is_meta; }; // 修改apply_modifier,添加Concept约束 template <MetaModifier Modifier, size_t N> static constexpr auto apply_modifier(Meta<N> meta, Modifier M) { return M.apply(meta); } // 原apply_modifiers保持不变,自动继承Concept约束 template <size_t N, MetaModifier FirstModifier, MetaModifier... RestModifiers> static constexpr auto apply_modifiers(Meta<N> meta, FirstModifier F, RestModifiers... rest) { return apply_modifiers(apply_modifier(meta, F), rest...); } template <size_t N> static constexpr auto apply_modifiers(Meta<N> meta) { return meta; }
当传入不符合要求的Modifier时,编译器会自动给出Concept不满足的提示,覆盖以下场景:
- Modifier没有
apply方法 apply方法参数不是Meta<N>apply返回值不是Meta<N2>
方式二:实现两步编译期检查(对应用户思路)
如果需要更自定义的错误提示,可以实现has_apply和is_meta_type两个辅助trait,在apply_modifier中分步检查:
#include <type_traits> // 辅助trait:判断类型是否为Meta的实例 template <typename T> struct is_meta_type : std::false_type {}; template <size_t N> struct is_meta_type<Meta<N>> : std::true_type {}; template <typename T> constexpr bool is_meta_type_v = is_meta_type<T>::value; // 辅助trait:判断Modifier是否拥有接受Meta<N>的apply方法 template <typename Modifier, typename MetaT, typename = void> struct has_apply : std::false_type {}; template <typename Modifier, size_t N> struct has_apply<Modifier, Meta<N>, std::void_t<decltype(std::declval<Modifier>().apply(std::declval<Meta<N>>()))>> : std::true_type {}; template <typename Modifier, typename MetaT> constexpr bool has_apply_v = has_apply<Modifier, MetaT>::value; // 修改apply_modifier,添加分步检查 template <typename Modifier, size_t N> static constexpr auto apply_modifier(Meta<N> meta, Modifier M) { if constexpr (!has_apply_v<Modifier, Meta<N>>) { static_assert(false, "错误:Modifier未定义签名为Meta<N2> apply(Meta<N>)的方法"); } else { auto r = M.apply(meta); if constexpr (!is_meta_type_v<decltype(r)>) { static_assert(false, "错误:Modifier的apply方法返回值不是Meta类型"); } else { return r; } } } // 原apply_modifiers函数保持不变 template <size_t N, typename FirstModifier, typename... RestModifiers> static constexpr auto apply_modifiers(Meta<N> meta, FirstModifier F, RestModifiers... rest) { return apply_modifiers(apply_modifier(meta, F), rest...); } template <size_t N> static constexpr auto apply_modifiers(Meta<N> meta) { return meta; }
这种方式可以提供更精准的自定义错误信息,帮助快速定位问题。
内容的提问来源于stack exchange,提问作者Jacky Lee
相关产品推荐
相关产品推荐

