【问题标题】:Return type of lambda in C++11 from inside the lambda (flat map function)从 lambda 内部返回 C++11 中的 lambda 类型(平面映射函数)
【发布时间】:2012-11-10 21:02:46
【问题描述】:

我在 scala 的平面地图上实现了一个函数,我想知道我是否可以在 lambda 中访问 lambda 的返回类型以避免在使用时重复它

/**
 * Inspired on scala's flat map, provide a @param func which output will be flattened in the output
 * sequence, which is the return type of @param func
 */
template <typename IN, typename F>
auto flat_mapf(const IN& input, F func)
    -> decltype(func(std::declval<typename IN::value_type>()))
{
    decltype(func(std::declval<typename IN::value_type>())) output;
    auto outit = std::back_inserter(output);
    for (auto i = input.begin(); i != input.end(); ++i)
    {
        decltype(func(std::declval<typename IN::value_type>())) interm = func(*i);
        std::move(interm.begin(), interm.end(), outit);
    }
    return output;
}


// usage example, I would like to avoid repeating vector<size_t> type two times:
auto vo = flat_mapf(vi, [](const size_t& x) -> vector<size_t> {
    vector<size_t> res;
    for (size_t i = 0; i < x; ++i)
        res.push_back(x);
    return res;
});

【问题讨论】:

  • 嗯?所以你想避免vector&lt;size_t&gt; 行中的vector&lt;size_t&gt; res;
  • 我可能错了,但我认为 lambdas 的返回类型是可选的。
  • 哇。你有什么错误,你必须重复两次vector&lt;size_t&gt;,而不是flat_mapf中的巨大decltype?备注:auto interm = func(*i);.
  • @Xeo - 库作者更关心flat_mapf用户 的体验而不是其内部实现的样子,这是可以理解的。除了实现之外,还有更多的用途(尤其是在这里,因为flat_mapf 是一元的“绑定”操作)。
  • @Daniel:除了 lambda 不是库的一部分,所以库作者无能为力。

标签: c++ c++11 lambda


【解决方案1】:

您不能在用法示例中省略-&gt; vector&lt;size_t&gt;,以便编译器推断出 lambda 的返回类型吗?这样你只说一次类型。

【讨论】:

  • lambda body 不是return expr;,所以这个不行,不行。
  • @Xeo - 有趣的是 Visual C++ 支持它就好了。它是特定于 MS 的扩展吗?
  • 好吧,它计划允许多个语句并仍然推断下一个标准的返回类型,但目前,是的,它是一个扩展(GCC 和 Clang IIRC 也支持)。 :)
  • @Daniel:或者他们遵循the proposalsdefect reports 的下一个标准。 ;)
  • 委员会对于添加无人知道其含义的新功能非常保守。相反,他们以受限制的形式添加它并在以后解除这些限制,这比其他方式更容易。
【解决方案2】:

由于您要提供的功能适用于范围(这是非常合理的事情),我可以为您指出 Boost.Range。用户可以将您的flat_mapf 与例如boost::irange 像这样:

auto vo = flat_mapf(vi, [](size_t x) {
    return boost::irange(size_t { 0 }, x);
 });

boost::irange 仅适用于整数类型,boost::counting_range 更通用。)

【讨论】:

    【解决方案3】:

    在这里返回一个实际的向量可能不是正确的方法。这需要在将每个元素的所有输出累积在一起之前生成和缓存。

    某种类型的生成器模式,例如返回可选提升的子映射函子(空表示已完成生成)等意味着您不需要中间容器。将这样的生成器转为标准向量很容易,当每个子图都是生成器 lambda 时,编写平面图也很容易。

    我提出这个是因为它也意味着双类型规范消失了。在三元运算符不起作用的情况下,您只有一个位置返回,然后另一个位置返回空。

    简而言之,也许您输入了很多标准向量,因为您制作了很多标准向量。

    【讨论】:

    • 我之前尝试过 boost::optional,看起来不错,但在调试器中使用起来很麻烦。将来我会避免过度设计,对我来说 optional now 只是一个可以为空的指针。至少我可以轻松检查它。
    • 这通常需要使用免费商店,这意味着所有的头痛。我的观点是,在模拟 C++ 中的函数式编程行为时,生成器(无论哪种方式——有很多方法)可能是比vector-builders 更好的方法。函数式语言通常会提取数据而不是推送数据。
    • 你能发布一个具体的例子来说明你的意思吗?不像用 C++ 表达生成器那么容易。在 python 中,我知道如何使用 yield 等来做到这一点。
    猜你喜欢
    • 2012-09-20
    • 2014-12-28
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多