返回模板 lambda 函数的正确方法是啥?
Posted
技术标签:
【中文标题】返回模板 lambda 函数的正确方法是啥?【英文标题】:What is the correct way to return a template lambda function?返回模板 lambda 函数的正确方法是什么? 【发布时间】:2021-10-30 14:42:18 【问题描述】:我正在用 C++ 中的 lambda 函数进行试验,我想制作一个大致相当于 Haskell 中的 take
函数的函数。
take :: Int -> [a] -> [a]
给定一个整数 n
和一个包含任何类型 a
的列表,它返回列表的第一个 n
元素。我试图用 C++ 中的柯里化函数来做到这一点,但遇到了使其成为多态的问题。我目前的非多态实现是这样的:
function<vector<int>(vector<int>)> take(int n)
return [=](vector<int> v)
v.resize(n);
return v;
;
这显然只适用于vector<int>
类型,我想知道如何使它在向量元素的类型中具有多态性。到目前为止,我已经尝试了此代码的一些变体:
template<typename T>
function<vector<T>(vector<T>)> take(int n)
return [=](vector<T> v)
v.resize(n);
return v;
;
但是当我尝试使用类似的东西部分应用该功能时
function<vector<int>(vector<int>)> take_2 = take(2);
我收到以下错误:
note: candidate template ignored: couldn't infer template argument 'T'
function<vector<T>(vector<T>)> take(int n)
^
非常感谢您对实现这一目标的任何帮助!
我对 C++ 中的模板和 lambdas 也非常缺乏经验,所以如果有更优雅的方法来解决这个问题,请告诉我。
【问题讨论】:
C++ 没有多态函数(没有模板)或健壮的类型推断。如果你需要 Haskell,你知道在哪里可以找到它。 Template instantiation can only deduce its parameters from the arguments 【参考方案1】:您应该返回一个带有模板化调用运算符的对象,该调用运算符可以使用resize
方法和复制/移动构造函数处理任何事情。一个 lambda 函数可以做到这一点:
#include <deque>
#include <cstdio>
auto take(size_t n)
return [n](auto container)
container.resize(n);
return container;
;
int main()
auto take_2 = take(2);
std::deque<int> d;
auto d2 = take_2(d);
std::printf("size of d2 is %zu\n", d2.size());
【讨论】:
【参考方案2】:take
是一个带有不可演绎模板参数的函数模板。当对应的函数形参依赖于模板形参时,可以从函数实参推导出模板形参;但int
不依赖于T
。
与其他一些语言中类型推断的工作方式不同,C++ 不允许从调用结果的使用方式中推断模板参数。
调用take
的唯一方法是显式指定模板参数,例如take<std::string>(42)
。
A Rank 2 Haskell 函数
take' :: int -> (forall a . [a] -> [a])
可以用一个 C++ 函数来近似,该函数返回一个带有operator()
成员模板的函数对象(例如 lambda):
#include <iostream>
#include <vector>
#include <string>
auto take(std::size_t n)
return [n](auto xs)
if (xs.size() > n)
xs.resize(n);
return x;
;
auto show(const auto& xs)
for (const auto& x: xs) std::cout << x << " ";
std::cout << "\n";
;
int main()
const auto take2 = take(2);
show(take2(std::vector1,2,3,4,5));
show(take2(std::vector"a","b","c","d","e"));
【讨论】:
以上是关于返回模板 lambda 函数的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
异步 Lambda 函数:返回 promise 或发送 responseURL 不会终止 CloudFormation 自定义资源调用