return 模板 lambda 函数的正确方法是什么?
What is the correct way to return a template lambda function?
我正在 C++ 中试验 lambda 函数,我想创建一个大致相当于 Haskell.
中的 take
函数的函数
take :: Int -> [a] -> [a]
给定一个整数 n
和一个包含任何类型 a
的列表,它 returns 是列表的前 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++ 中的模板和 lambda 也很缺乏经验,所以如果有更优雅的方法来解决这个问题,请告诉我。
您应该 return 一个具有模板化调用运算符的对象,该对象可以使用 resize
方法和 copy/move 构造函数处理任何事情。 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());
}
take
是一个带有不可推导模板参数的函数模板。当相应的函数参数依赖于模板参数时,可以从函数参数中推导出模板参数;但是 int
不依赖于 T
.
与类型推断在某些其他语言中的工作方式相反,C++ 不允许从使用调用结果的方式推断模板参数。
调用take
的唯一方法是显式指定模板参数,例如take<std::string>(42)
。
排名 2 Haskell 的函数
take' :: int -> (forall a . [a] -> [a])
可以用一个 C++ 函数来近似,该函数 returns 一个具有 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::vector{1,2,3,4,5}));
show(take2(std::vector{"a","b","c","d","e"}));
}
我正在 C++ 中试验 lambda 函数,我想创建一个大致相当于 Haskell.
中的take
函数的函数
take :: Int -> [a] -> [a]
给定一个整数 n
和一个包含任何类型 a
的列表,它 returns 是列表的前 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++ 中的模板和 lambda 也很缺乏经验,所以如果有更优雅的方法来解决这个问题,请告诉我。
您应该 return 一个具有模板化调用运算符的对象,该对象可以使用 resize
方法和 copy/move 构造函数处理任何事情。 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());
}
take
是一个带有不可推导模板参数的函数模板。当相应的函数参数依赖于模板参数时,可以从函数参数中推导出模板参数;但是 int
不依赖于 T
.
与类型推断在某些其他语言中的工作方式相反,C++ 不允许从使用调用结果的方式推断模板参数。
调用take
的唯一方法是显式指定模板参数,例如take<std::string>(42)
。
排名 2 Haskell 的函数
take' :: int -> (forall a . [a] -> [a])
可以用一个 C++ 函数来近似,该函数 returns 一个具有 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::vector{1,2,3,4,5}));
show(take2(std::vector{"a","b","c","d","e"}));
}