C++03环境下如何从模板类中剔除针对void类型的函数
在C++03中为智能指针模板类剔除void类型的operator*函数
要在C03中实现仅针对非void类型保留operator*,同时避免全类特化,可以利用SFINAE结合函数模板参数推导(避开C03不支持函数模板默认参数的限制),具体实现如下:
核心思路
- 保留原有的
EnableIfNotVoid特性模板,用于在T为void时禁用类型定义。 - 将
operator*改为函数模板,通过参数推导绑定U与类模板参数T,同时利用SFINAE在U为void时剔除该函数。
完整代码示例
template<typename T> struct EnableIfNotVoid { typedef T type; }; template<> struct EnableIfNotVoid<void> {}; template<typename T> class SmartPtr { public: // 利用参数推导绑定U与T,无需函数模板默认参数 template<typename U> typename EnableIfNotVoid<U>::type& operator*(U* = content) const { return *content; } private: T* content; }; int main(int, char **) { SmartPtr<int> works; SmartPtr<void> noWork; int& i = *works; // 正常编译 // *noWork; // 编译报错,符合预期:无匹配的operator* }
方案解释
- 当调用
*works时,编译器会推导U为int(因为content是int*),此时EnableIfNotVoid<int>::type有效,函数正常参与重载决议并生成。 - 当
T为void时,推导U为void,EnableIfNotVoid<void>没有定义type,根据SFINAE规则,该函数模板会被从重载候选中剔除,不会引发编译错误,同时SmartPtr<void>也就没有可用的operator*。 - 该方案无需全类特化,仅针对单个函数做处理,符合你的需求。
为什么之前的方案失败
- 移除默认参数:函数模板无法推导
U的类型,导致找不到匹配的operator*。 - 移除函数模板:类实例化时会直接检查返回类型,
EnableIfNotVoid<void>::type不存在会直接报错,SFINAE无法生效(SFINAE仅作用于模板函数的重载决议阶段)。 - 不使用SFINAE:直接返回
T&会在T=void时触发“形成void引用”的编译错误。
内容的提问来源于stack exchange,提问作者Refugnic Eternium
相关产品推荐
相关产品推荐

