C++:使用同名但参数不同的 class 成员和静态函数失败
C++: using class member and static function of same name but different parameters fails
我想要一个 class,它有一个静态函数和一个同名的成员函数,并且做完全相同的事情。一次能够从实例中调用它,一次将它与标准算法中的函数一起使用。最小示例:
#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 都发生了可怕的错误。 clang 错误是
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报错基本一样,只是写法不同
我显然做错了,但我目前不知道如何解决这个问题。任何指点表示赞赏。
当获取指向重载方法的指针时,您需要告诉编译器您希望将指针指向哪个重载,您可以通过静态转换为适当的方法类型来做到这一点:
auto numones=std::count_if(v.begin(), v.end(), static_cast<bool(*)(const foo&)>(foo::isOne));
还有其他几种方法可以解决这个问题,即:
- 创建静态成员,友元函数
- 使用 lambda
我推荐第二种,那就这样吧:
auto numones=std::count_if(v.begin(), v.end(), [](foo const& f) { return foo::is one(f); });
此解决方案允许您保留这两个功能并且不会引入任何歧义。
问题是因为count_if
是函数模板,不是函数。
非static
成员不适合count_if
这一事实在推断模板参数的类型时没有考虑。
如果您的 class 过载
,您会发现同样的错误
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
成员函数移出 class。使其成为全局函数或您自己的应用程序的命名空间中的函数。
#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.
我想要一个 class,它有一个静态函数和一个同名的成员函数,并且做完全相同的事情。一次能够从实例中调用它,一次将它与标准算法中的函数一起使用。最小示例:
#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 都发生了可怕的错误。 clang 错误是
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报错基本一样,只是写法不同
我显然做错了,但我目前不知道如何解决这个问题。任何指点表示赞赏。
当获取指向重载方法的指针时,您需要告诉编译器您希望将指针指向哪个重载,您可以通过静态转换为适当的方法类型来做到这一点:
auto numones=std::count_if(v.begin(), v.end(), static_cast<bool(*)(const foo&)>(foo::isOne));
还有其他几种方法可以解决这个问题,即:
- 创建静态成员,友元函数
- 使用 lambda
我推荐第二种,那就这样吧:
auto numones=std::count_if(v.begin(), v.end(), [](foo const& f) { return foo::is one(f); });
此解决方案允许您保留这两个功能并且不会引入任何歧义。
问题是因为count_if
是函数模板,不是函数。
非static
成员不适合count_if
这一事实在推断模板参数的类型时没有考虑。
如果您的 class 过载
,您会发现同样的错误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
成员函数移出 class。使其成为全局函数或您自己的应用程序的命名空间中的函数。
#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.