为什么在 std::transform 中使用函数对象参数失败并且需要 lambda 表达式

Why does using a function object argument in std::transform fail and require a lambda expression instead

本文关键字:失败 表达式 lambda 参数 函数 transform std 为什么 对象      更新时间:2023-10-16

从这个问题中,我对函子(函数对象)有了很好的理解;如何初始化和调用它们。我写了一些代码来玩这个,供我自己理解

class Foo
{
private:
   int x;
public:
   Foo(int x) : x(x) {}
   int operator()(int y) { return x + y; }
};
Foo poo(50);
int a = poo(50);
std::cout << a;
std::vector<int> vec(10);
std::vector<int> pec(10);
std::transform(vec.begin(), vec.end(), vec.begin(), poo(1));

并收到以下编译错误

Severity    Code    Description Project File    Line    Suppression State
Error   C2064   term does not evaluate to a function taking 1 arguments 

我在上面的问题中查看了一些评论,并尝试了 lambda 表达式

std::transform(vec.begin(), vec.end(), vec.begin(), [](Foo poo) {return poo(1); });

这有效,但我不明白为什么使用 std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 的接受答案失败了。 为什么我必须使用 lambda 表达式? 另一个答案是做同样的事情,但它仍然会导致编译错误。 为什么?

这段代码工作得很好。

#include <iostream>
#include <array>
class add_x
{
private:
   int x;
public:
   add_x(int x) : x(x) {}
   int operator()(int y) /* consider adding const here */
   { return x + y; }
};

int main()
{
    std::array<int, 5> input { 1, 4, 9, 16, 25 };
    std::array<int, 5> output;
    std::transform(begin(input), end(input), begin(output), add_x(1));
    for ( auto& val : output ) std::cout << val << "n";
}

但是,将调用设置为const成员函数可能是个好主意,因为它不会改变函子。 这也可能使其适用于更多版本的标准库。

此版本与您的 lambda 版本之间的区别在于,此处将常量1传递给构造函数以创建一个函子对象,数据将按顺序传递给该单个函子实例的运算符。 在您的 lambda 中,通过调用转换构造函数从每个基准面创建一个新对象,然后将常量传递给运算符。 也就是说,您的解决方法会交换xy,并且更改的实例数也会交换。

如果您添加定义,它也可以工作:

Foo poo(1);

并且只需将便便发送到转换中,而无需 (1) 调用。转换需要一个带有 () 运算符的对象来调用,单独声明它会使它的作用域更加清晰一些。