C++中模板函数为何默认匹配float而非double?
问题背景
我知道可以通过重载或在模板中使用多个typename来解决此问题,只是想学习模板的工作原理,弄清楚当前遇到的情况。
以下是测试代码(故意假设所有参数为同一类型):
template <typename T> inline T saturate(T val, T lower, T upper) { T val1 = val > lower ? val : lower; T val2 = val1 < upper ? val1 : upper; return val2; } int main() { double v = 1.234; saturate(v, 0.0, 90.0); return 0; }
编译后出现错误:
no matching function for call to 'saturate(double&, float, float)'
根据C++标准,无后缀的浮点字面量默认类型应为double:
The type of a floating literal is double unless explicitly specified by a suffix. The suffixes f and F specify float, the suffixes l and L specify long double.
但编译器却将0.0和90.0视为float,我想知道原因。再次说明:我知道有多种修复方法,只是想理解这个错误的原因!
补充:之前未考虑到这可能是编译器特定问题,我使用的编译命令为 arm-none-eabi-g++ -std=c++14 -std=gnu++14
原因分析
首先确认:你对C++标准的理解完全正确,无后缀浮点字面量的默认类型确实是double。
你遇到的问题是ARM交叉编译器的平台特定行为导致的:
arm-none-eabi-g++是针对嵌入式ARM平台的专用编译器,这类编译器会优先适配嵌入式设备的硬件资源限制。当你启用-std=gnu++14选项时,编译器开启了GNU扩展;如果目标ARM平台没有硬件双精度浮点单元(FPU),或者默认浮点ABI设置为soft/softfp,编译器会将无后缀浮点字面量默认转为float——这是为了避免双精度浮点运算带来的额外性能开销和内存占用,是嵌入式场景下的优化策略。
结合模板参数推导规则来看:
你的模板要求三个参数必须是同一类型T,调用时第一个参数是double类型变量v,而后两个字面量被编译器识别为float。模板参数推导过程中,编译器不会自动进行隐式类型转换来统一参数类型,因此无法推导出一个符合所有参数的T,最终抛出“找不到匹配函数”的错误。
如果需要验证这一点,可以尝试添加-mfloat-abi=hard编译选项(前提是目标平台支持硬件双精度浮点),此时编译器会遵循C++标准将无后缀浮点字面量识别为double,模板推导也会正常完成。
内容的提问来源于stack exchange,提问作者KevbotInControl

