为啥捕获 lambda 不能应用于 std::valarray?

Posted

技术标签:

【中文标题】为啥捕获 lambda 不能应用于 std::valarray?【英文标题】:Why the capturing lambda cannot be applied to the std::valarray?为什么捕获 lambda 不能应用于 std::valarray? 【发布时间】:2017-09-03 11:49:07 【问题描述】:

什么不符合捕获 lambda 被传递给 std::valarrayapply 方法的条件? 考虑以下代码:

int main()

    std::valarray<int> arr = 1, 2, 3, 4, 5, 6;
    auto arr1 = arr.apply([](int val)  return val * 2; ); // compiles
    int n = 3;
    auto arr2 = arr.apply([n](int val)  return val * n; ); //does not compile
    return 0;

住在科里鲁http://coliru.stacked-crooked.com/a/f0407046699574fc

在 https://gcc.godbolt.org/ 上测试GCC、MSVC 或 CLang 都不能编译上述代码

【问题讨论】:

【参考方案1】:

原因在std::valarray::apply的定义中:

valarray<T> apply( T func(T) ) const;
valarray<T> apply( T func(const T&) ) const;

两个成员中func 的类型都是函数类型。当用作另一个函数的参数类型时,它会衰减为函数指针。这些成员函数不接受通用函子。只有指向常规函数的指针。

现在,无捕获 lambda 具有到函数指针的隐式转换运算符。所以第一个 lambda 被转换为 int(*)(int),这是一个可以执行 lambda 主体的常规函数​​的地址。

但是捕获状态的 lambda 不能以这种方式转换,并且如您所见,不能作为参数传递给 std::valarray::apply

【讨论】:

知道为什么要这样做吗?可能是因为它会使矢量化或并行化优化不适用于此类apply 实现? @kreuzerkrieg - std::valarray 早在我们将 lambdas 引入该语言之前就已经构思好了。另外,我想这是为了鼓励传递“纯”功能。我知道,在现代 C++ 中,这一点很突出。 嗯...他们为 valarrays 添加了 C++11 的 std::begin/end 特化,为什么不添加其余的现代东西...嗯,我猜只是 valarray 不是与其他 STL 容器一样广泛使用。 @kreuzerkrieg - 可能。必须有人为此编写提案才能将其引入标准。如果用的不多,估计没人会写。

以上是关于为啥捕获 lambda 不能应用于 std::valarray?的主要内容,如果未能解决你的问题,请参考以下文章

如果 lambda 使用 std::move() 捕获不可复制的对象,为啥它是不可移动的?

在 Java Lambda 中,为啥在捕获的变量上调用 getClass()

为啥 lambda init-capture 对 unique_ptr 不起作用?

为啥 Lambda 变量范围存在于 LINQ 查询之外?

使用 lambda 创建 std::function 会导致多余的 lambda 对象复制 - 为啥?

为啥我不能在 C++11 中创建一个 lambda 向量(相同类型)?