代码之家  ›  专栏  ›  技术社区  ›  BaCh

C++:使用名称相同但参数不同的类成员和静态函数失败

  •  3
  • BaCh  · 技术社区  · 6 年前

    我希望有一个具有相同名称的静态函数和成员函数的类,并执行完全相同的操作。一次可以从实例调用它,一次可以将它与std算法中的函数一起使用。最小示例:

    #include <algorithm>
    #include <vector>
    
    class foo {
    public:
      inline static bool isOne(const foo & s) {
        return s.bar == 1;
      }
      // if I uncomment the next line, count_if won't compile anymore
      //inline bool isOne() const { return isOne(*this); }
    
    private:
      int bar;
    };
    
    int main()
    {
      std::vector<foo> v;
      auto numones=std::count_if(v.begin(), v.end(), foo::isOne);
      return 0;
    }
    

    上述代码按预期编译和工作。但是,如果我取消对成员函数isOne()的注释,因为我可能还希望

    foo x; x.isOne();
    

    在我的main()中,clang 6.0和gcc 5.3的情况都非常糟糕。叮当声错误为

    no matching function for call to 'count_if'
    note: candidate template ignored: couldn't infer template argument '_Predicate'
    count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred)
    

    gcc错误在不同的措辞中基本相同。

    我显然做错了,但我目前不知道如何解决这个问题。感谢您的指点。

    3 回复  |  直到 6 年前
        1
  •  3
  •   Alan Birtles    6 年前

    在将指针指向重载方法时,需要告诉编译器要将指针指向哪个重载,可以通过对适当的方法类型进行静态转换来实现这一点:

     auto numones=std::count_if(v.begin(), v.end(), static_cast<bool(*)(const foo&)>(foo::isOne));
    
        2
  •  1
  •   R Sahu    6 年前

    问题的原因是 count_if 是函数模板,不是函数。

    事实上- static 成员不适合 count\u如果 在推断模板参数的类型时不考虑。

    如果您的类过载,您会注意到相同的错误

    inline static bool isOne(const foo & s, int) { ... }
    

    解决此问题的唯一方法是帮助编译器解决重载问题。通过显式转换函数

    auto numones = std::count_if(v.begin(), v.end(),
                                 static_cast<bool(&)(const foo&)>(foo::isOne));
    

    或者使用显式模板参数。

    auto numones = std::count_if<decltype(v.begin()),  // First template parameter
                                 bool(&)(const foo&)>  // Second template parameter
                                 (v.begin(), v.end(), foo::isOne);
    

    您可以通过遵循良好的软件工程实践来避免这些问题。

    移动 静止的 类外的成员函数。将其设置为全局函数或您自己应用程序的命名空间中的函数。

    #include <algorithm>
    #include <vector>
    
    namespace MyApp
    {
       class foo {
          public:
             inline bool isOne() const { return (bar == 1); }
    
          private:
             int bar;
       };
    
       inline bool isOne(foo const& s)
       {
          return s.isOne();
       }
    }
    
    int main()
    {
      std::vector<MyApp::foo> v;
      auto numones=(v.begin(), v.end(), MyApp::isOne);
      return 0;
    }
    

    有鉴于此,您可以使用ADL调用函数的命名空间版本,而无需显式使用 MyApp::isOne

    MyApp::foo f;
    isOne(f);   // OK. Uses ADL to find the right function.
    
        3
  •  0
  •   smac89    6 年前

    有几种其他方法可以解决此问题,即:

    • 使静态成员成为友元函数
    • 使用lambda

    我推荐第二种,也可以这样做:

    auto numones=std::count_if(v.begin(), v.end(), [](foo const& f) { return foo::is one(f); });
    

    此解决方案允许您保留这两个函数,并且不会引入任何歧义。