我想知道是否有人可以帮助我使用仿函数。我真的不明白是什么算子以及它们是如何工作的我已经尝试使用谷歌搜索它但我仍然没有得到它。仿函数如何工作以及它们如何使用模板
答案 0 :(得分:6)
仿函数基本上是一个“函数对象”。它是一个包含在类或结构中的单个函数,您可以将其传递给其他函数。
它们通过创建自己的类或结构来工作,该类重载函数调用操作符(称为operator())。通常,您可以通过简单地将其作为函数的参数构建它来创建它的实例,该函数需要一个仿函数。
假设您有以下内容:
std::vector<int> counts;
现在,您想要增加该向量中包含的所有计数。您可以手动循环它们以递增它们,或者您可以使用仿函数。在这种情况下,合适的函子看起来像这样:
struct IncrementFunctor
{
int operator() (int i)
{
return i + 1;
}
}
IncrementFunctor现在是一个仿函数,它接受任何整数并递增它。要将它应用于计数,可以使用std :: transform函数,它将仿函数作为参数。
std::transform(
counts.begin(), // the start of the input range
counts.end(), // the end of the input range
counts.begin(), // the place where transform should place new values.
// in this case, we put it right back into the original list.
IncrementFunctor()); // an instance of your functor
语法IncrementFunctor()创建该仿函数的一个实例,然后直接传递给std :: transform。当然,您可以将实例创建为局部变量并将其传递,但这样更方便。
现在,进入模板。 std :: transform中的仿函数类型是模板参数。这是因为std :: transform不知道(或关心!)你的仿函数是哪种类型。所有它关心的是它有一个适合的operator()定义,它可以做类似
的事情newValue = functor(oldValue);
编译器对模板非常聪明,并且通常可以自己弄清楚模板参数是什么。在这种情况下,编译器会自动实现您传入的类型为IncrementFunctor的参数,该参数在std :: transform中定义为模板类型。它对列表也是如此,因此编译器会自动识别实际调用如下所示:
std::transform<std::vector<int>::iterator, // type of the input iterator
std::vector<int>::iterator, // type of the output iterator
IncrementFunctor>( // type of your functor
counts.begin(), // the start of the input range
counts.end(), // the end of the input range
counts.begin(), // the place where transform should place new values.
// in this case, we put it right back into the original list.
IncrementFunctor()); // an instance of your functor
它可以为您节省大量的打字费用。 ;)
答案 1 :(得分:5)
可以使用函数调用运算符调用/调用仿函数,在语法上通过附加()
,在括号内可选地包含参数列表。
这就是模板的全部需求。就模板而言,调用它的东西是允许这种语法的任何东西 - 换句话说,是自由函数或覆盖operator()()
的类的实例。 (“自由”函数只是一个不是成员的函数,也就是说,它是全局范围内的函数或以前包含的命名空间范围内的函数。)
在模板元编程之外,我们通常不会说自由函数是一个函子,并为一个覆盖operator()()
的类的实例保留该名称:
struct Foo {
public:
void operator()( int i ) { // do something }
void operator()( int i, char x ) { // do something else }
}
在C ++模板中编译,只要语法有意义,编译器就会愉快地使用函数或函子:
template<typename T> class Bar {
private int j ;
public:
Bar( int i ) : j(i) {}
void doIt(T t) {
t( j ) ;
}
}
Foo f;
extern void resize( int i ) ; // in some header
Bar<Foo> bf( 5 ) ;
// a Bar that is templated on Foo
Bar< void (&)(int) > br( 5 ) ;
// a Bar that is templated on a function taking int and returning void
br.doit( &resize ) ; // call resize with br.j
bf.doit( f ) ; // call Foo::operator()(int) on Foo f with bf.j