这可能是一个天真的问题,但无论如何它仍然存在:
假设我有这样一个类:
class func {
public:
int operator()(int it) const { return it + 21; }
};
很明显,在上面的类中定义了一个仿函数,如果我这样做:
func obj;
int capture = obj(9);
cout << capture << endl;
结果将是30,显而易见。但是假设我使用std::transform
根据上面定义的仿函数使用另一个容器的值来转换一个容器。
vector<int> v, vi;
v.push_back(1);
v.push_back(2);
vi.resize(v.size());
我按照下面的语法,我使用类名直接调用仿函数,并且没有参数传递给仿函数(根据定义它需要):
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
中正确使用仿函数?为什么调用functor方法的方式有所不同?
另外,从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)
在这里扮演一个仿函数(而不是一个实例),在上面给出的例子中,它是如何实现的?
答案 0 :(得分:4)
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
// ^^^^^^^^^^^^^^^^^
这不是在调用lambda_function::operator()
,它只是创建lambda_function
的临时实例。在std::transform
内,此对象将以operator()
的内容作为参数迭代调用其v
。
如果您使用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);
构造函数。这会初始化函数对象中的某个状态,以便在operator()
内调用std::transform
时,它会添加给定的数字。
答案 1 :(得分:3)
在此,
std::transform(v.begin(), v.end(), vi.begin(), lambda_function());
lambda_function()
默认 - 创建lambda_function
的临时实例
lambda_function
是一个类,而不是一个对象
lambda_function()
是一个对象。
在
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance());
您没有通过该实例,而是试图在没有参数的情况下调用operator()
。
instance
是一个对象,而不是一个类。
要传递实例,请写
lambda_function instance;
std::transform(v.begin(), v.end(), vi.begin(), instance);
答案 2 :(得分:3)
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()
。
答案 3 :(得分:0)
看到区别:
lambda_function obj;
int capture = obj(9);
cout << capture << endl;
VS
int capture = lambda_function()(9);
cout << capture << endl;
和第二个例子:
std::transform(v.begin(), v.end(). vi.begin(), lambda_function());
vs
lambda_function obj;
std::transform(v.begin(), v.end(). vi.begin(), obj);
最新的例子:
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
VS
add_x obj( 1 );
std::transform(in.begin(), in.end(), out.begin(), obj);