【问题标题】:How to deduce the return type of a lambda?如何推断 lambda 的返回类型?
【发布时间】:2019-11-10 10:28:15
【问题描述】:

我想在 C++ 中模仿 Ruby 的 map() 方法。我正在努力自动找出返回类型:

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>

typedef std::string T2;

template<class T1,
//  class T2, // gives "couldn't deduce template parameter 'T2'"
    class UnaryPredicate>
std::vector<T2> map(std::vector<T1> in, UnaryPredicate pred)
{
    std::vector<T2> res(in.size());
    std::transform(in.begin(), in.end(), res.begin(), pred);
    return res;
}

int main()
{
    std::vector<int> v1({1,2,3});
    auto v2(map(v1, [](auto el) { return "'"+std::to_string(el+1)+"'"; }));
    std::cout << v2[0] << "," << v2[1] << "," << v2[2] << std::endl;
}

这样编译,但T2 固定为string。如果我使用另一个T2 定义,编译器会抱怨couldn't deduce template parameter 'T2'。 我也尝试过使用std::declval,但可能不是正确的方式——我无法解决问题。

【问题讨论】:

  • 欢迎来到 Stack Overflow!仅供参考,请注意主函数的正确签名是int main()
  • 模仿map 不一定是个好主意,因为我们有范围。 ranges::view::transform 是惯用且高效的,如果您需要副本而不是视图,只需复制视图即可。
  • @ruohola 这并非不可能,但很可能是遗留的implicit-int 规则启动了。一些编译器仍然默认实现它。例如,请参阅implicit int and implicit declaration of functions with gcc compiler

标签: c++ templates lambda template-argument-deduction generic-lambda


【解决方案1】:

使用decltype + std::decay_t:

template <class T, class UnaryPredicate>
auto map(const std::vector<T>& in, UnaryPredicate pred)
{
    using result_t = std::decay_t<decltype(pred(in[0]))>;

    std::vector<result_t> res;
    res.reserve(in.size());
    std::transform(in.begin(), in.end(), std::back_inserter(res), pred);
    return res;
}

示例用法:

std::vector v1{1, 2, 3};
auto v2 = map(v1, [](int el) { return "'" + std::to_string(el + 1) + "'"; });
std::cout << v2[0] << ", " << v2[1] << ", " << v2[2] << '\n';

(live demo)

还请注意我所做的以下更改:

  1. 我将in 更改为按常量引用而不是按值获取。这样可以避免不必要的复制。

  2. 我使用了reserve + back_inserter,而不是值初始化+赋值。

  3. 我使用auto 作为返回类型。这将启用返回类型扣除。 res 向量保证不会被复制。它也符合复制省略的条件。

  4. 您可以直接从 braced-init-list 进行列表初始化,因此请删除 braced-init-list 周围的括号。

  5. std::endl 不应该在 \n 足够时使用。 std::endl 会刷新缓冲区,而\n 不会。不必要的刷新会导致性能下降。见std::endl vs \n

【讨论】:

    【解决方案2】:

    为了简化使用auto作为返回类型,向量的value_type可以由declval指定——调用UnaryPredicateT1

    template<class T1,
        class UnaryPredicate>
    auto map(std::vector<T1> in, UnaryPredicate pred)
    {
        std::vector< decltype(std::declval<UnaryPredicate>()(T1{})) > res(in.size());
        std::transform(in.begin(), in.end(), res.begin(), pred);
        return res;
    }
    

    Demo

    【讨论】:

      猜你喜欢
      • 2021-10-23
      • 2020-11-05
      • 2013-12-05
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      相关资源
      最近更新 更多