std::max 统一初始化和 constexpr int 表现出意外
std::max behaves unexpected with uniform initialization and constexpr int
我正在试验 std::max。我试图通过统一初始化(花括号)传递整数 constexpr,以将它们与浮点变量进行比较。
实验 a):调用 std::max() 与 double/int 混合
double a = 3.0;
int b = 5;
auto res = std::max(a, b);
不编译。 Clang 报告 error: no matching function for call to 'max'
。这当然可以。
实验b):使用大括号+constexpr int进行非逆向转换
double a = 3.0;
constexpr int b = 5;
auto res = std::max(a, {b});
按预期编译和工作:returns 值为 5.0 的双精度值。
实验 c):与 b) 相同,但交换 std::max.
的参数
double a = 3.0;
constexpr int b = 5;
auto res = std::max({b}, a);
在 gcc 和 clang 下都不编译。为什么?
Clang 报告 error: called object type 'double' is not a function or function pointer
。
存在 std::max
的重载,如下所示(来自 cppreference.com):
template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );
这比
更适合您的通话 auto res = std::max({b}, a);
template< class T >
constexpr const T& max( const T& a, const T& b );
您正在尝试调用,因为 {b}
可以推断为 std::initializer_list<int>
并且该调用在两个参数中都具有完全匹配的转换等级,而您要调用的重载需要从 int
到 double
的转换不是完全匹配。
第二个参数被认为是比较操作调用的Compare
仿函数,但是调用double
显然失败了。如果第二个参数不可调用,则重载不会被禁用,这就是它仍然被选中的原因。
auto res = std::max(a, {b});
不会发生这种情况,因为第二个参数没有 std::initializer_list
参数的重载,因此只有您要调用的重载是可行的。初始化列表使第二个参数成为非推导上下文,这就是为什么它与 auto res = std::max(a, b);
不同的原因,后者由于两个参数之间的模板参数推导不匹配而失败。
在你的第三个 'experiment' 中,你有一个初始化列表作为 std::max
的第一个参数;因此,编译器试图使用以下模板 (see cppreference):
template< class T, class Compare >
T max( std::initializer_list<T> ilist, Compare comp );
其中第二个参数需要是一个比较函数。
我正在试验 std::max。我试图通过统一初始化(花括号)传递整数 constexpr,以将它们与浮点变量进行比较。
实验 a):调用 std::max() 与 double/int 混合
double a = 3.0;
int b = 5;
auto res = std::max(a, b);
不编译。 Clang 报告 error: no matching function for call to 'max'
。这当然可以。
实验b):使用大括号+constexpr int进行非逆向转换
double a = 3.0;
constexpr int b = 5;
auto res = std::max(a, {b});
按预期编译和工作:returns 值为 5.0 的双精度值。
实验 c):与 b) 相同,但交换 std::max.
的参数 double a = 3.0;
constexpr int b = 5;
auto res = std::max({b}, a);
在 gcc 和 clang 下都不编译。为什么?
Clang 报告 error: called object type 'double' is not a function or function pointer
。
存在 std::max
的重载,如下所示(来自 cppreference.com):
template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );
这比
更适合您的通话auto res = std::max({b}, a);
template< class T >
constexpr const T& max( const T& a, const T& b );
您正在尝试调用,因为 {b}
可以推断为 std::initializer_list<int>
并且该调用在两个参数中都具有完全匹配的转换等级,而您要调用的重载需要从 int
到 double
的转换不是完全匹配。
第二个参数被认为是比较操作调用的Compare
仿函数,但是调用double
显然失败了。如果第二个参数不可调用,则重载不会被禁用,这就是它仍然被选中的原因。
auto res = std::max(a, {b});
不会发生这种情况,因为第二个参数没有 std::initializer_list
参数的重载,因此只有您要调用的重载是可行的。初始化列表使第二个参数成为非推导上下文,这就是为什么它与 auto res = std::max(a, b);
不同的原因,后者由于两个参数之间的模板参数推导不匹配而失败。
在你的第三个 'experiment' 中,你有一个初始化列表作为 std::max
的第一个参数;因此,编译器试图使用以下模板 (see cppreference):
template< class T, class Compare >
T max( std::initializer_list<T> ilist, Compare comp );
其中第二个参数需要是一个比较函数。