如何推导 lambda 的 return 类型?

How to deduce the return type of a lambda?

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

#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,但可能不是正确的方法 - 我无法解决问题。

为了简化使用 auto 作为 return 类型,向量的 value_type 可以由 declval 指定 - 为 [=15= 调用 UnaryPredicate ]:

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

使用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 更改为按 const 引用而不是按值。这避免了不必要的复制。

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

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

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

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