在 std::for_each 和 std::transform 中正确使用函子
Proper use of a functor in std::for_each and std::transform
这可能是一个幼稚的问题,但无论如何:
假设我有一个像这样的 class :
class func {
public:
int operator()(int it) const { return it + 21; }
};
很明显,上面定义了一个仿函数 class,如果我这样做:
func obj;
int capture = obj(9);
cout << capture << endl;
很明显,结果将是 30。但是假设我使用 STL std::transform
根据上面定义的仿函数使用另一个容器的值来转换一个容器:
vector<int> v, vi;
v.push_back(1);
v.push_back(2);
vi.resize(v.size());
我遵循以下语法,其中我直接使用 class-name 调用仿函数,而且,没有参数传递给仿函数(根据定义它需要):
std::transform(v.begin(), v.end(), vi.begin(), func());
这非常有效。为什么会这样?尽管没有使用 func
的实例并且也没有传递参数(这显然是第一个容器的元素),但为什么这样做有效?
此外,如果我像上面那样使用带有参数的 func
实例,则会导致编译错误。
func instance;
std::transform(v.begin(), v.end(), vi.begin(), instance());
如何在std::transform/std::for_each
中正确使用函子?为什么调用仿函数方法的方式不同?
此外,从this answer on functors,我们有以下代码:
// this is a functor
struct add_x {
add_x(int x) : x(x) {}
int operator()(int y) const { return x + y; }
private:
int x;
};
std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
答案说add_x(1)
在这里充当了一个仿函数(而不是一个实例),它在我上面的例子中是一个实例吗?
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
// ^^^^^^^^^^^^^^^^^
这不是调用 lambda_function::operator()
,它只是创建 lambda_function
的临时实例。在 std::transform
内,此对象将使用 v
的内容作为参数迭代调用其 operator()
。
如果使用 C++11 的大括号初始化,会发生什么更明显:
std::transform(v.begin(), v.end(), vi.begin(), lambda_function{});
或者如果你考虑这个:
lambda_function()(0);
// ^^ creates instance
// ^^^ calls operator()
关于你的第二个例子:
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
// ^^^^^^^^
这将再次创建 add_x
的临时实例,但它不会调用默认构造函数,而是调用 add_x(int x);
构造函数。这会初始化函数对象中的某些状态,以便在 std::transform
中调用 operator()
时,它会添加给定的数字。
在此,
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
lambda_function()
default-creates lambda_function
.
的临时实例
lambda_function
是一个 class,不是对象。
lambda_function()
是一个对象。
在
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance());
您没有传递实例,您正在尝试调用不带参数的 operator()
。
instance
是一个对象,而不是 class。
要传递实例,写
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance);
std::transform(InIt first, InIt last, OutIt dest, Fn f)
本质上是这样做的:
while (first != last) {
*dest = f(*first);
first++;
}
所以当你打电话时
std::transform(v.begin(), v.end(). vi.begin(), lambda_function());
您正在创建类型为 lambda_function
的临时对象并将该对象传递给 transform
。在 transform
中,该对象在输入范围的每个元素上被调用,就像在您的代码 int capture = obj(9);
.
中一样
要使用您已经创建的对象而不是临时对象,只需将其传入:
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance);
注意这段代码在instance
之后没有()
;那将是不带参数调用 operator()
,而 lambda_function
没有可以不带参数调用的 operator()
。
看区别:
lambda_function obj;
int capture = obj(9);
cout << capture << endl;
对
int capture = lambda_function()(9);
cout << capture << endl;
第二个例子:
std::transform(v.begin(), v.end(). vi.begin(), lambda_function());
对比
lambda_function obj;
std::transform(v.begin(), v.end(). vi.begin(), obj);
最新示例:
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
对
add_x obj( 1 );
std::transform(in.begin(), in.end(), out.begin(), obj);
这可能是一个幼稚的问题,但无论如何:
假设我有一个像这样的 class :
class func {
public:
int operator()(int it) const { return it + 21; }
};
很明显,上面定义了一个仿函数 class,如果我这样做:
func obj;
int capture = obj(9);
cout << capture << endl;
很明显,结果将是 30。但是假设我使用 STL std::transform
根据上面定义的仿函数使用另一个容器的值来转换一个容器:
vector<int> v, vi;
v.push_back(1);
v.push_back(2);
vi.resize(v.size());
我遵循以下语法,其中我直接使用 class-name 调用仿函数,而且,没有参数传递给仿函数(根据定义它需要):
std::transform(v.begin(), v.end(), vi.begin(), func());
这非常有效。为什么会这样?尽管没有使用 func
的实例并且也没有传递参数(这显然是第一个容器的元素),但为什么这样做有效?
此外,如果我像上面那样使用带有参数的 func
实例,则会导致编译错误。
func instance;
std::transform(v.begin(), v.end(), vi.begin(), instance());
如何在std::transform/std::for_each
中正确使用函子?为什么调用仿函数方法的方式不同?
此外,从this answer on functors,我们有以下代码:
// this is a functor
struct add_x {
add_x(int x) : x(x) {}
int operator()(int y) const { return x + y; }
private:
int x;
};
std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
答案说add_x(1)
在这里充当了一个仿函数(而不是一个实例),它在我上面的例子中是一个实例吗?
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
// ^^^^^^^^^^^^^^^^^
这不是调用 lambda_function::operator()
,它只是创建 lambda_function
的临时实例。在 std::transform
内,此对象将使用 v
的内容作为参数迭代调用其 operator()
。
如果使用 C++11 的大括号初始化,会发生什么更明显:
std::transform(v.begin(), v.end(), vi.begin(), lambda_function{});
或者如果你考虑这个:
lambda_function()(0);
// ^^ creates instance
// ^^^ calls operator()
关于你的第二个例子:
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
// ^^^^^^^^
这将再次创建 add_x
的临时实例,但它不会调用默认构造函数,而是调用 add_x(int x);
构造函数。这会初始化函数对象中的某些状态,以便在 std::transform
中调用 operator()
时,它会添加给定的数字。
在此,
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
lambda_function()
default-creates lambda_function
.
的临时实例
lambda_function
是一个 class,不是对象。
lambda_function()
是一个对象。
在
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance());
您没有传递实例,您正在尝试调用不带参数的 operator()
。
instance
是一个对象,而不是 class。
要传递实例,写
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance);
std::transform(InIt first, InIt last, OutIt dest, Fn f)
本质上是这样做的:
while (first != last) {
*dest = f(*first);
first++;
}
所以当你打电话时
std::transform(v.begin(), v.end(). vi.begin(), lambda_function());
您正在创建类型为 lambda_function
的临时对象并将该对象传递给 transform
。在 transform
中,该对象在输入范围的每个元素上被调用,就像在您的代码 int capture = obj(9);
.
要使用您已经创建的对象而不是临时对象,只需将其传入:
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance);
注意这段代码在instance
之后没有()
;那将是不带参数调用 operator()
,而 lambda_function
没有可以不带参数调用的 operator()
。
看区别:
lambda_function obj;
int capture = obj(9);
cout << capture << endl;
对
int capture = lambda_function()(9);
cout << capture << endl;
第二个例子:
std::transform(v.begin(), v.end(). vi.begin(), lambda_function());
对比
lambda_function obj;
std::transform(v.begin(), v.end(). vi.begin(), obj);
最新示例:
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
对
add_x obj( 1 );
std::transform(in.begin(), in.end(), out.begin(), obj);