Function objects
函数对象是专门设计用于与函数语法相似的语法的对象。在C++中,这是通过在类中定义成员函数运算符()来实现的,例如:
struct myclass {
int operator()(int a) {return a;}
} myobject;
int x = myobject (0); // function-like syntax with object myobject
它们通常用作函数的参数,例如传递给标准算法的predicates或comparison functions。
Functions
These functions create objects of wrapper classes based on its arguments:
bind
simple(1) | template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args); |
---|---|
with return type (2) | template <class Ret, class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args); |
绑定函数参数
返回一个基于fn的函数对象,但其参数绑定到args。
每个参数可以绑定到一个值,也可以是一个占位符:
-如果绑定到某个值,则调用返回的函数对象将始终使用该值作为参数。
-如果是占位符,则调用返回的函数对象会转发传递给调用的参数(占位符指定其序号的参数)。 调用返回的对象将返回与fn相同的类型,除非将特定的返回类型指定为Ret(2)(请注意,Ret是传递给此函数的参数无法隐式推导的唯一模板参数)。
返回对象的类型具有以下属性:
它的函数调用返回与fn相同的结果,其参数绑定到args。。。(或转发,用于占位符)。
对于(1),它可能有一个成员result_type:如果Fn是指向函数或成员函数类型的指针,则它被定义为其返回类型的别名。否则,如果存在这样的成员类型,则将其定义为Fn::result_type。
对于(2),它有一个成员result_type,定义为Ret的别名。
它是可移动构造的,如果它所有参数的类型都是可复制构造的,那么它也是可复制构造。两个构造函数都从不抛出,前提是没有Fn和Args衰变类型的相应构造函数。。。投
// bind example
#include <iostream> // std::cout
#include <functional> // std::bind
// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide (double x, double y) {return x/y;}
struct MyPair {
double a,b;
double multiply() {return a*b;}
};
int main () {
using namespace std::placeholders; // adds visibility of _1, _2, _3,...
// binding functions:
auto fn_five = std::bind (my_divide,10,2); // returns 10/2
std::cout << fn_five() << '\n'; // 5
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x
std::cout << fn_invert(10,2) << '\n'; // 0.2
auto fn_rounding = std::bind<int> (my_divide,_1,_2); // returns int(x/y)
std::cout << fn_rounding(10,3) << '\n'; // 3
MyPair ten_two {10,2};
// binding members:
auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
std::cout << bound_member_fn(ten_two) << '\n'; // 20
auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
std::cout << bound_member_data() << '\n'; // 10
return 0;
}
Output:
5 5 0.2 3 20 10 |
cref
reference (1) | template <class T> reference_wrapper<const T> cref (const T& elem) noexcept; |
---|---|
copy (2) | template <class T> reference_wrapper<const T> cref (reference_wrapper<T>& x) noexcept; |
move (3) | template <class T> void cref (const T&&) = delete; |
构造const的reference_wrapper
构造一个具有适当reference_wrapper类型的对象,以保存对elem的const T引用。
如果参数本身是常量T(2)的reference_wrapper,则它会创建x的副本。
该函数调用正确的reference_wrapper构造函数。
// cref example
#include <iostream> // std::cout
#include <functional> // std::ref
int main () {
int foo (10);
auto bar = std::cref(foo);
++foo;
std::cout << bar << '\n';
return 0;
}
Output:
11 |
mem_fn
template <class Ret, class T> /* unspecified */ mem_fn (Ret T::* pm);
将成员函数转换为函数对象
返回一个函数对象,其函数调用调用pm所指向的成员函数。
返回对象的类型具有以下属性:
它的函数调用将T类型的对象(或指向它的引用或指针)作为第一个参数,并将pm所采用的参数(如果有的话)作为附加参数。以fn作为第一个参数的这种调用的效果与调用fn.*pm(或(*fn).*pm,如果fn是指针),转发任何其他参数相同。
它有一个成员result_type,定义为Ret的别名(这是pm的返回类型)。
如果pm指向的成员不带参数,则它有一个成员argument_type,定义为T*的别名。
如果pm指向的成员采用一个参数,则其成员first_argument_type(定义为T*的别名)和成员second_argument_type(定义为由pm采用的参数的别名)。
它是可构造的,可构造的和可分配的。
// mem_fn example
#include <iostream> // std::cout
#include <functional> // std::mem_fn
struct int_holder {
int value;
int triple() {return value*3;}
};
int main () {
int_holder five {5};
// call member directly:
std::cout << five.triple() << '\n';
// same as above using a mem_fn:
auto triple = std::mem_fn (&int_holder::triple);
std::cout << triple(five) << '\n';
return 0;
}
Output:
15 15 |
not1
template <class Predicate> unary_negate<Predicate> not1 (const Predicate& pred);
返回一元函数对象的否定
构造一个一元函数对象(一元否定类型),该对象返回与pred相反的值(由运算符返回!)。
它的定义与以下行为相同:
template <class Predicate> unary_negate<Predicate> not1 (const Predicate& pred)
{
return unary_negate<Predicate>(pred);
}
// not1 example
#include <iostream> // std::cout
#include <functional> // std::not1
#include <algorithm> // std::count_if
struct IsOdd {
bool operator() (const int& x) const {return x%2==1;}
typedef int argument_type;
};
int main () {
int values[] = {1,2,3,4,5};
int cx = std::count_if (values, values+5, std::not1(IsOdd()));
std::cout << "There are " << cx << " elements with even values.\n";
return 0;
}
// not1 example
#include <iostream> // std::cout
#include <functional> // std::not1
#include <algorithm> // std::count_if
struct IsOdd {
bool operator() (const int& x) const {return x%2==1;}
typedef int argument_type;
};
int main () {
int values[] = {1,2,3,4,5};
int cx = std::count_if (values, values+5, std::not1(IsOdd()));
std::cout << "There are " << cx << " elements with even values.\n";
return 0;
}
Output:
There are 2 elements with even values. |
not2
template <class Predicate> binary_negate<Predicate> not2 (const Predicate& pred);
返回二元函数对象对象的否定
构造一个二元函数对象(binary_enegate类型),该对象返回与pred相反的值(由运算符返回!)。 它的定义与以下行为相同:
template <class Predicate> binary_negate<Predicate> not2 (const Predicate& pred)
{
return binary_negate<Predicate>(pred);
}
// not2 example
#include <iostream> // std::cout
#include <functional> // std::not2, std::equal_to
#include <algorithm> // std::mismatch
#include <utility> // std::pair
int main () {
int foo[] = {10,20,30,40,50};
int bar[] = {0,15,30,45,60};
std::pair<int*,int*> firstmatch,firstmismatch;
firstmismatch = std::mismatch (foo, foo+5, bar, std::equal_to<int>());
firstmatch = std::mismatch (foo, foo+5, bar, std::not2(std::equal_to<int>()));
std::cout << "First mismatch in bar is " << *firstmismatch.second << '\n';
std::cout << "First match in bar is " << *firstmatch.second << '\n';
return 0;
}
First mismatch in bar is 0 First match in bar is 30 |
ref
reference (1) | template <class T> reference_wrapper<T> ref (T& elem) noexcept; |
---|---|
copy (2) | template <class T> reference_wrapper<T> ref (reference_wrapper<T>& x) noexcept; |
move (3) | template <class T> void ref (const T&&) = delete; |
构造reference_wrapper
构造一个具有适当reference_wrapper类型的对象来保存对elem的引用。
如果参数本身是reference_wrapper(2),则它会创建x的副本。
该函数调用正确的reference_wrapper构造函数。
// ref example
#include <iostream> // std::cout
#include <functional> // std::ref
int main () {
int foo (10);
auto bar = std::ref(foo);
++bar;
std::cout << foo << '\n';
return 0;
}
Output:
11 |