自定义类型特性检测带模板参数的成员函数时失效的问题排查
自定义类型特性检测带模板参数的成员函数时失效的问题排查
哎呀,太懂你这种“单独测试逻辑明明对,放到类型特性里就翻车”的抓狂感了!咱们来一步步揪出问题根源。
问题核心:模板成员函数的调用歧义
你在类型特性偏特化里写的declval<T>().serialize<Endian::LITTLE>(),这里藏着一个极易踩的语法坑:当T是未知模板参数时,编译器没办法自动识别serialize是模板成员函数,它会把<>当成小于号来解析,直接导致这个偏特化分支被SFINAE规则排除,最终类型特性只能匹配到默认的false_type。
那为什么单独写static_assert时能正常运行?因为在那个上下文里,编译器已经能看到Serialize的具体定义,明确知道serialize是模板函数,所以能正确解析调用;但在类型特性的偏特化阶段,T是泛型参数,编译器没有提前判断T成员属性的依据,这时候必须手动明确告知它。
解决方案:用template关键字明确模板调用
只需要在调用模板成员函数前加上template关键字,告诉编译器后面的<>是模板参数列表,而非比较运算符:
修正后的类型特性偏特化代码如下:
template <typename T> struct is_serializable< T, enable_if_t< is_same_v< decltype(declval<T>().template serialize<Endian::LITTLE>(declval<gsl::span<uint8_t>>())), gsl::span<uint8_t> > && is_same_v< decltype(declval<T>().template serialize<Endian::BIG>(declval<gsl::span<uint8_t>>())), gsl::span<uint8_t> > > > : true_type {};
顺带修正小细节
另外你代码里还有两个小疏漏,顺手补上更稳妥:
Endian枚举定义末尾缺分号:
enum class Endian { LITTLE, BIG }; // 补上分号
Serialize的serialize函数返回语句缺分号:
template <Endian endian> gsl::span<uint8_t> serialize(gsl::span<uint8_t> input) { return input; // 补上分号 }
修改完成后,你的static_assert(is_serializable_v<Serialize>, "***");就能正常通过啦!
备注:内容来源于stack exchange,提问作者Benjamin
相关产品推荐
相关产品推荐

