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

时间:2018-03-10 21:08:56

标签: function c++11 static stl member

我希望有一个类具有静态和具有相同名称的成员函数,并且执行完全相同的操作。一旦能够从一个实例调用它,一次使用它与std-algorithm的函数。最小的例子:

#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 个答案:

答案 0 :(得分:3)

当获取指向重载方法的指针时,你需要告诉编译器你想要指向哪个重载,你可以使用静态强制转换为适当的方法类型:

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

答案 1 :(得分:1)

问题是由count_if是函数模板而非函数引起的。

在推断模板参数的类型时,不考虑非static成员不适合count_if这一事实。

如果您的课程有重载,您会注意到同样的错误

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);

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

static成员函数移出课程。使其成为您自己的应用程序的命名空间中的全局函数或函数。

#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.

答案 2 :(得分:0)

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

  • 制作静态成员,朋友功能
  • 使用lambda

我推荐第二个,所以这样做:

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

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