C++20中Concept限制函数模板重载出现调用歧义原因问询
自定义Concept导致函数模板重载歧义的原因分析
问题重现
用户尝试通过自定义Concept区分浮点和非浮点类型的函数模板重载,代码如下:
#include <iostream> #include <string> #include <vector> #include <type_traits> #include <concepts> template< typename T> concept NotFloatingPoint = requires { !std::is_same_v<T, double> || !std::is_same_v<T, float>; }; template< NotFloatingPoint T, NotFloatingPoint U, bool isDistanceType_ = false > void ProcConstantConfigForce( T& value_ ) { std::cout << "Inside ProcConstantConfigForce()\n"; std::cout << value_; } template< typename T> concept FloatingPoint = requires { std::is_same_v<T, double> || std::is_same_v<T, float>; }; template< FloatingPoint T, FloatingPoint U, bool isDistanceType_ = false > void ProcConstantConfigForce( T& value_ ) { std::cout << "Inside ProcConstantConfigForce() for doubles\n"; std::cout << value_; if ( isDistanceType_ ) { value_ *= 1.5; } } #define FORCE_CONSTANT( constant_, isDistanceType_ ) ProcConstantConfigForce< decltype( constant_ ), decltype( constant_ ), isDistanceType_ > int main() { double val = 1.0; FORCE_CONSTANT(1.0, true)(val); std::cout << "Updated val: " << val; }
编译时出现歧义错误:
main.cpp:43:3: error: call to 'ProcConstantConfigForce' is ambiguous FORCE_CONSTANT(1.0, true)(val); ^~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:38:54: note: expanded from macro 'FORCE_CONSTANT' #define FORCE_CONSTANT( constant_, isDistanceType_ ) ProcConstantConfigForce< decltype( constant_ ), decltype( constant_ ), isDistanceType_ > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:14:6: note: candidate function [with T = double, U = double, isDistanceType_ = true] void ProcConstantConfigForce( T& value_ ) ^ main.cpp:27:6: note: candidate function [with T = double, U = double, isDistanceType_ = true] void ProcConstantConfigForce( T& value_ ) ^ 1 error generated.
核心原因
自定义NotFloatingPoint概念的逻辑完全错误:
- 原条件
!std::is_same_v<T, double> || !std::is_same_v<T, float>的语义是只要类型不是double,或者不是float就满足条件。 - 对于
double类型,!is_same_v<double, double>为false,但!is_same_v<double, float>为true,false || true的结果是true,所以NotFloatingPoint<double>会被判定为true。 - 这就导致
double类型同时满足NotFloatingPoint和FloatingPoint两个概念,两个重载模板都能成功实例化,编译器无法确定调用哪一个,从而引发歧义。
修正方案
方案1:修复NotFloatingPoint的逻辑
将逻辑运算符从||改为&&,表示类型既不是double也不是float:
template< typename T> concept NotFloatingPoint = requires { !std::is_same_v<T, double> && !std::is_same_v<T, float>; };
方案2:复用FloatingPoint概念简化约束
直接用requires (!FloatingPoint<T>)代替自定义的NotFloatingPoint,避免重复定义逻辑:
template< typename T, typename U, bool isDistanceType_ = false > requires (!FloatingPoint<T> && !FloatingPoint<U>) void ProcConstantConfigForce( T& value_ ) { std::cout << "Inside ProcConstantConfigForce()\n"; std::cout << value_; }
方案3:使用标准库std::floating_point概念
C++20标准库提供了现成的std::floating_point概念,无需自定义:
// 浮点版本 template<std::floating_point T, std::floating_point U, bool isDistanceType_ = false> void ProcConstantConfigForce(T& value_) { /* ... */ } // 非浮点版本 template<typename T, typename U, bool isDistanceType_ = false> requires (!std::floating_point<T> && !std::floating_point<U>) void ProcConstantConfigForce(T& value_) { /* ... */ }
内容的提问来源于stack exchange,提问作者Alexander the Great
相关产品推荐
相关产品推荐

