std::max 在统一初始化和 constexpr int 下表现出乎意料

CN8*_*N85 5 c++ std max constexpr

我正在试验 std::max。我想通过统一初始化(花括号)传递整数 constexpr,以将它们与浮点变量进行比较。

实验 a):用 double/int 混合调用 std::max()

    double a = 3.0;
    int b = 5;
    auto res = std::max(a, b);
Run Code Online (Sandbox Code Playgroud)

不编译。铿锵报告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});
Run Code Online (Sandbox Code Playgroud)

编译并按预期工作:返回值为 5.0 的双精度值。

实验 c):与 b) 相同,但交换 std::max 的参数。

    double a = 3.0;
    constexpr int b = 5;
    auto res = std::max({b}, a);
Run Code Online (Sandbox Code Playgroud)

不能在 gcc 和 clang 下编译。为什么?

铿锵报告error: called object type 'double' is not a function or function pointer

wal*_*nut 5

存在一个std::max看起来像这样的重载(来自cppreference.com):

template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );
Run Code Online (Sandbox Code Playgroud)

auto res = std::max({b}, a);比您的呼叫更适合

template< class T >
constexpr const T& max( const T& a, const T& b );
Run Code Online (Sandbox Code Playgroud)

您正在尝试调用它,因为{b}可以推导出来std::initializer_list<int>并且该调用在两个参数中都具有完全匹配的转换等级,而您要调用的重载需要从不完全匹配的转换intdouble

然后将第二个参数视为Compare要为比较操作调用的函子,但调用 adouble显然失败了。如果第二个参数不可调用,则不会禁用重载,这就是仍然选择它的原因。

这不会发生在auto res = std::max(a, {b});,因为std::initializer_list第二个参数没有带参数的重载,因此只有您想要调用的重载是可行的。初始值设定项列表使第二个参数成为非推导的上下文,这就是它与 形成对比的原因auto res = std::max(a, b);,后者由于两个参数之间的模板参数推导不匹配而失败。