如何推导 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;
}
使用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';
另请注意我所做的以下更改:
我将 in
更改为按 const 引用而不是按值。这避免了不必要的复制。
我用的是reserve
+back_inserter
,而不是值初始化+赋值
我使用 auto
作为 return 类型。这会启用 return 类型推导。 res
向量保证不会被复制。它也符合复制省略的条件。
您可以直接从 braced-init-list 进行列表初始化,因此移除 braced-init-list 周围的括号.
当 \n
足够时,不应使用 std::endl
。 std::endl
导致缓冲区被刷新,而 \n
则不会。不必要的冲洗会导致性能下降。见 std::endl
vs \n
.
我想在 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;
}
使用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';
另请注意我所做的以下更改:
我将
in
更改为按 const 引用而不是按值。这避免了不必要的复制。我用的是
reserve
+back_inserter
,而不是值初始化+赋值我使用
auto
作为 return 类型。这会启用 return 类型推导。res
向量保证不会被复制。它也符合复制省略的条件。您可以直接从 braced-init-list 进行列表初始化,因此移除 braced-init-list 周围的括号.
当 std::endl
。std::endl
导致缓冲区被刷新,而\n
则不会。不必要的冲洗会导致性能下降。见std::endl
vs\n
.
\n
足够时,不应使用