You need to enable JavaScript to run this app. 使用SFINAE实现类型检查报错,test函数参数末尾*号的作用是什么?
优惠活动
大模型
产品
解决方案
定价
更多

使用SFINAE实现类型检查报错,test函数参数末尾*号的作用是什么?

两种写法效果不同的核心原因

两种写法的差异本质是重载决议阶段的参数匹配规则不同,和SFINAE的替换逻辑本身没有直接关联:

1. 指针参数版本正常工作的逻辑

当test参数为reallyHas<string (C::*)(), &C::serialize>*指针类型时:

  • 你调用test<T>(0)时传入的实参0是空指针常量,可以合法隐式转换为任意类型的空指针
  • 如果T存在对应签名的serialize成员函数,reallyHas的模板参数就能成功实例化,这个模板重载的优先级远高于接收任意参数的test(...)兜底重载,会被优先选中,sizeof计算得到yes类型的大小,最终value为true
  • 如果T不存在对应签名的函数,模板替换失败触发SFINAE,这个重载被移出候选集,最终匹配到兜底重载,value为false

2. 值参数版本失效的逻辑

当去掉*改为值类型reallyHas<string (C::*)(), &C::serialize>时:

  • 你传入的实参是int类型的0,而reallyHas是没有自定义构造函数的空结构体,不存在从int到reallyHas实例的合法隐式转换路径
  • 哪怕T存在对应签名的serialize函数、reallyHas模板可以正常实例化,这个重载本身也会因为参数类型不匹配被直接排除在候选集之外,最终只会匹配到test(...)兜底重载,所以不管有没有对应函数,value永远是false,检测逻辑失效。

值参数版本的修正方案

如果想要用值类型参数也能正常工作,可以给test函数加上默认参数,调用时不需要传实参即可:

template<typename T>
struct has_serialize {
    typedef char yes[1];
    typedef char no[2];

    template<typename U, U u> struct reallyHas{}; 

    template <typename C>
    static yes& test(reallyHas<string (C::*)(), &C::serialize> = {}){}

    // 针对const方法的重载
    template<typename C>
    static yes& test(reallyHas<string (C::*)() const, &C::serialize> = {}){}

    template<typename>
    static no& test(...){}

    enum {
         value = (sizeof(test<T>()) == sizeof(yes))
    };
};

内容的提问来源于stack exchange,提问作者Bad_Panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 10:36:03