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"}));
}