我希望有一个类具有静态和具有相同名称的成员函数,并且执行完全相同的操作。一旦能够从一个实例调用它,一次使用它与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错误在不同的措辞中基本相同。
我显然做错了,但我目前没有想法如何解决这个问题。任何指针都赞赏。
答案 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)
还有其他几种方法可以解决这个问题,即:
我推荐第二个,所以这样做:
auto numones=std::count_if(v.begin(), v.end(), [](foo const& f) { return foo::is one(f); });
此解决方案允许您保留这两个功能,并且不会引入任何歧义。