仿函数基本上是一个"函数对象".它是一个包含在类或结构中的单个函数,您可以将其传递给其他函数.
它们通过创建自己的类或结构来工作,该类重载函数调用操作符(称为operator()).通常,您可以通过简单地将其作为函数的参数构建它来创建它的实例,该函数使用仿函数.
假设您有以下内容:
std::vector<int> counts;
Run Code Online (Sandbox Code Playgroud)
现在,您想要增加该向量中包含的所有计数.您可以手动循环它们以递增它们,或者您可以使用仿函数.在这种情况下,合适的函子看起来像这样:
struct IncrementFunctor
{
int operator() (int i)
{
return i + 1;
}
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
语法IncrementFunctor()创建该仿函数的一个实例,然后直接传递给std :: transform.当然,您可以将实例创建为局部变量并将其传递,但这样更方便.
现在,进入模板.std :: transform中的仿函数类型是模板参数.这是因为std :: transform不知道(或关心!)你的仿函数是哪种类型.所有它关心的是它有一个适合的operator()定义,它可以做类似的事情
newValue = functor(oldValue);
Run Code Online (Sandbox Code Playgroud)
编译器对模板非常聪明,并且通常可以自己弄清楚模板参数是什么.在这种情况下,编译器会自动实现您传入的类型为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
Run Code Online (Sandbox Code Playgroud)
它可以节省你很多的打字.;)
仿函数是可以使用函数调用运算符调用/调用的东西,通过附加语法(),可选地在括号内包含参数列表.
这都是模板需求.就模板而言,调用它的东西是允许这种语法的任何东西 - 换句话说,就是自由函数或覆盖的类的实例operator()().("自由"函数只是一个不是成员的函数,也就是说,它是全局范围内的函数或以前包含的命名空间范围内的函数.)
在模板元编程之外,我们通常不会说自由函数是一个函子,并为一个覆盖的类的实例保留该名称operator()():
struct Foo {
public:
void operator()( int i ) { // do something }
void operator()( int i, char x ) { // do something else }
}
Run Code Online (Sandbox Code Playgroud)
在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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
905 次 |
| 最近记录: |