代码之家  ›  专栏  ›  技术社区  ›  Toby Speight

为什么我不能将std::isfinite<double>作为谓词函数传递?

  •  4
  • Toby Speight  · 技术社区  · 8 月前

    我正试图通过一个特定的过载 std::isfinite() 到函数,但GCC拒绝:

    0.cpp:9:24: error: no matching function for call to ‘all_of(std::array<double, 2>::const_iterator, std::array<double, 2>::const_iterator, <unresolved overloaded function type>)’
        9 |     return !std::all_of(a.begin(), a.end(), std::isfinite<double>);
          |             ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    来源如下:

    #include <algorithm>
    #include <array>
    #include <cmath>
    
    int main()
    {
        auto const a = std::array<double, 2>{{0.0, 1.0}};
        return !std::all_of(a.begin(), a.end(), std::isfinite<double>);
    }
    

    它为什么考虑 std::isfinite<double> 作为一个未解析的重载函数类型,有没有比封装自己的lambda函数更简单的解决方案?我宁愿不用写 [](double x){ return std::isfinite(x); } 如果我不需要的话。

    这是我在以前使用Microsoft编译器编译的一些代码中遇到的,但它不是为我使用GCC构建的。

    如果重要的话,我在尝试的所有标准版本中都看到了相同的症状: -std=c++11 , -std=c++17 -std=c++23 .

    2 回复  |  直到 8 月前
        1
  •  5
  •   Ahmed AEK    8 月前

    通常情况下,您不能指望标准库中没有其他重载。


    这也意味着标准库中的函数不能取其地址,除非它们被明确标记为可寻址函数。

    同样对于自定义函数,也没有“指向重载集的指针”这样的东西。在存在不同重载的情况下,要获得指针,您必须选择其中一个重载:

     void foo(int);
     void foo(double);
     auto ptr = &foo;                              // error
     auto ptr = static_cast<void(*)(int)>(foo);    // ok
    

    或者将重载解析推迟到实际调用函数时(请参见下文)。


    从…起 cppreference 关于 std::isfinite :

    为所有整数类型提供了额外的重载,这些类型被视为double。

    不需要完全按照(A)提供额外的过载。他们只需要足够确保他们的论点 num 为整数类型, std::isfinite(num) 具有与相同的效果 std::isfinite(static_cast<double>(num)) .

    您可以将其封装在lambda中:

    std::all_of(a.begin(), a.end(),[](auto x){ return std::isfinite(x);});
    
        2
  •  3
  •   Ahmed AEK    8 月前

    你实际上不能打电话 std::isfinite<double>(5.0) 因为模板参数仅适用于Integer类型。

    接受的过载 double 只是一个重载,而不是模板,您只需要转换为正确的重载。

    std::all_of(a.begin(), a.end(), static_cast<bool(*)(double)>(std::isfinite));