SFINAE检测类型有无unsigned等价实现为何对float类型报错
问题原因
- SFINAE机制仅对函数模板参数替换的直接上下文中出现的错误生效,替换过程中触发其他模板内部的错误属于硬错误,不会被SFINAE忽略,会直接终止编译。
- 按照C++标准规定,
std::make_unsigned的模板参数必须为整数类型或枚举类型,传入其他类型(如float)属于未定义行为。主流标准库实现中,传入非整数类型时std::make_unsigned<T>会被定义为不完整类型,你代码中对不完整类型求sizeof的错误发生在std::make_unsigned的实例化内部,不属于hasUnsigned模板替换的直接上下文,因此编译器不会将该重载从候选集移除,而是直接报错。
修复方案
你可以先对模板参数做整数类型约束,避免对非整数类型实例化std::make_unsigned,修正后的代码如下:
#include <type_traits> #include <iostream> template <typename T> std::enable_if_t<std::is_integral_v<T> && sizeof(typename std::make_unsigned<T>::type), bool> hasUnsigned(T x) { return true; } bool hasUnsigned(...) { return false; } int main() { float x; std::cout << std::boolalpha << hasUnsigned(x) << std::endl; // 输出 false std::cout << hasUnsigned(int{}) << std::endl; // 输出 true std::cout << hasUnsigned(bool{}) << std::endl; // 输出 true }
如果你使用C++20及以上版本,也可以用concept简化写法:
#include <type_traits> #include <iostream> template<typename T> concept has_unsigned = std::is_integral_v<T> && requires { typename std::make_unsigned<T>::type; }; bool hasUnsigned(auto x) { return has_unsigned<decltype(x)>; } int main() { float x; std::cout << std::boolalpha << hasUnsigned(x) << std::endl; // 输出 false std::cout << hasUnsigned(int{}) << std::endl; // 输出 true std::cout << hasUnsigned(bool{}) << std::endl; // 输出 true }
内容的提问来源于stack exchange,提问作者user3882729
相关产品推荐
相关产品推荐

