为何std::numeric_limits<自定义结构体>::infinity()可编译并返回默认对象?
std::numeric_limits<somestruct>::infinity()能编译并返回默认构造对象? 这事儿得从std::numeric_limits的设计逻辑说起:
默认模板特化的兜底行为:C++标准里,
std::numeric_limits是一个通用模板类,它的主模板(未针对特定类型特化的版本)会为所有类型提供默认的成员函数实现——哪怕这个类型不是算术类型。对于infinity()这个成员函数,默认实现就是返回T(),也就是默认构造的T对象。只有算术类型才有专属特化:像
int、double这些内置算术类型,标准库提供了std::numeric_limits的特化版本,其中infinity()会返回对应类型的无穷大值(比如double的正无穷)。但你的somestruct是自定义结构体,不属于标准规定的算术类型,所以编译器会使用主模板的默认实现。编译合法性的原因:只要你的自定义类型满足模板成员函数的要求,就能正常实例化。这里
infinity()需要somestruct可以默认构造——而你的结构体不仅有编译器自动合成的默认构造函数,还为成员a设置了默认初始化值,完全符合要求,所以编译器不会报错。
回到你的测试代码,std::numeric_limits<somestruct>::infinity()实际上就是调用了somestruct(),也就是创建了一个默认构造的对象,所以输出的a值是你设置的默认值7,完全符合默认模板的行为逻辑。
如果想让std::numeric_limits对somestruct有自定义的行为,你可以手动特化这个模板,比如:
namespace std { template<> class numeric_limits<somestruct> { public: static constexpr bool has_infinity = true; static constexpr somestruct infinity() noexcept { return somestruct{UINT64_MAX}; // 自定义你的"无穷大"对象 } }; }
这样再调用infinity()时,就会返回你定义的专属值了。
内容的提问来源于stack exchange,提问作者Bomaz

