【问题标题】:Passing lambda as a template parameter? ( c++20, lambdas in unevaluated context)将 lambda 作为模板参数传递? (c++20,未评估上下文中的 lambdas)
【发布时间】:2020-12-21 09:40:34
【问题描述】:

我知道之前有人问过这个问题,但他们都没有解决 c++20 lambdas。

我一直在研究 c++20 的新功能,其中一个引起我注意的是在未评估的上下文中使用 lambdas 的可能性。

我看到您可以在 Jason Turner 的视频中编写如下代码:

std::unique_ptr<int, decltype([] (FILE* f) {fclose(f);})>;

这表明std::unique_ptr 可以采用 lambda 参数。

所以我尝试实现一个类似惰性数学的序列类,如下所示:

#include <vector>
#include <iostream>
template <typename func, typename T> 
struct Sequence
{
    T operator[] (int i) {
        return func(i);
    }
};
int main() {

    auto u = std::vector{1 , 2, 3, 4};
    auto v= Sequence<decltype([u] (int i) {return u[i];}) , int>();
    std::cout << v[1];
    return 0;
}

这个想法是序列类被定义为一个从 N -> T 的函数(就像在数学中一样),并且我在编译时将此函数作为模板参数传递。 但是,我收到错误“没有匹配的 lambda 调用”。 怎么解决?

我可以在运行时将函数存储在 std::function 中,但我负担不起它带来的开销。

【问题讨论】:

  • 提示:func 是 lambda 的类型,而不是 lambda 本身。要获取 lambda 本身,您需要将它传递到某个地方
  • @user202729 如果每个 lambda 具有不同的类型,我不能调用 lambda 吗?另外,如果我不能,Jason Turner 的 std::unique_ptr 示例如何工作?它肯定会调用 lambda 吗?
  • Lambda 可以从 c++20 中的类型默认构造。但是你不能默认构造一个捕获 lambda。
  • @super 如果我传入一个非捕获的 lambda,我仍然会得到同样的错误,即 [] (int i) {return i;}
  • 那是因为你试图调用类型,而不是创建一个 lambda 实例并调用它。看看here

标签: c++ lambda c++20


【解决方案1】:

正如 cmets 中所述,问题在于您的 lambda 捕获了u。因此,您不能仅从 C++20 中的类型实例化 lambda。但是,如果您将 lambda 直接作为参数而不是其类型传递,并且使用数组而不是向量(vector's 构造函数和 operator[] 不是 constexpr),则可以使其工作:

#include <array>
#include <iostream>
template <auto func> 
struct Sequence
{
    consteval auto operator[] (int i) const {
        return func(i);
    }
};
int main() {
    constexpr auto u = std::array<int, 4>({1, 2, 3, 4});
    constexpr auto l = [=](int i) { return u[i]; };
    constexpr auto v = Sequence<l>{};
    static_assert(v[1] == 2);
    std::cout << v[1];
    return 0;
}

即使没有启用优化,operator[] 也不会在运行时调用。

【讨论】:

  • 谢谢。这回答了我的问题。我真正想要的是不要在编译时评估序列,即它可能取决于运行时类型,例如 std::vector。但我想这是不可能的......
  • 其实在 C++20 上,vector 已经改了,可以在compile time 使用,但似乎还没有被 gcc 接受(constexpr auto u = std::vector&lt;int&gt;{1, 2, 3, 4}; 失败)。您可以获得在编译时创建的序列,该序列在运行时评估了operator[],但其状态也必须在编译时可构造。例如,要将其用于向量,您需要将向量作为额外的方法参数传递。
猜你喜欢
  • 2020-09-13
  • 2017-06-14
  • 2019-08-23
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 2019-11-15
  • 2016-08-21
  • 1970-01-01
相关资源
最近更新 更多