如何创建一个可变的通用lambda?

时间:2014-09-17 08:37:37

标签: c++ lambda c++14 variadic

从C ++ 14开始,我们可以使用泛型lambdas:

auto generic_lambda = [] (auto param) {};

这基本上意味着它的调用操作符基于标记为auto的参数进行模板化。

问题是如何创建一个可以接受可变参数数量的lambda,类似于可变参数函数模板的工作方式?如果这不可能,最接近的东西可以用同样的方法吗? 你会怎么存储它?可以在std::function吗?

3 个答案:

答案 0 :(得分:38)

我不确定你的意图是什么,但不是将它存储在std::function中,你可以使用lambda本身捕获params。 这是在boost邮件列表中讨论的示例。它用于boost::hana实现

auto list = [](auto ...xs) {
    return [=](auto access) { return access(xs...); };
};

auto head = [](auto xs) {
    return xs([](auto first, auto ...rest) { return first; });
};

auto tail = [](auto xs) {
    return xs([](auto first, auto ...rest) { return list(rest...); });
};

auto length = [](auto xs) {
    return xs([](auto ...z) { return sizeof...(z); });
};

// etc...
// then use it like

auto three = length(list(1, '2', "3")); 

答案 1 :(得分:29)

语法

如何创建可变参数通用lambda?

您可以使用以下语法创建可变参数lambda:

auto variadic_generic_lambda = [] (auto... param) {};

基本上,您只需在...(可能是ref qualified)和参数包名称之间添加auto

所以通常使用通用引用会给出:

auto variadic_generic_lambda = [] (auto&&... param) {};

用法

您如何使用参数?

您应该将variadic泛型参数视为具有模板参数包类型,因为它就是这种情况。这或多或少意味着大多数(如果不是全部)这些参数的使用将需要模式的一种或另一种。

这是一个典型的例子:

#include <iostream>

void print(void)
{
}

template <typename First, typename ...Rest>
void print(const First& first, Rest&&... Args)
{
  std::cout << first << std::endl;
  print(Args...);
}

int     main(void)
{
  auto variadic_generic_lambda = [] (auto... param)
    {
      print(param...);
    };

  variadic_generic_lambda(42, "lol", 4.3);
}

存储

如何存储可变参数的通用lambda?

您可以使用auto将lambda存储在自己类型的变量中,也可以将其存储在std::function中,但只能使用固定签名调用它给了std::function

auto variadic_generic_lambda = [] (auto... param) {};

std::function<void(int, int)> func = variadic_generic_lambda;

func(42, 42); // Compiles

func("lol"); // Doesn't compile

可变参数lambda的集合怎么样?

由于每个lambda都有不同的类型,因此无法将其直接类型存储在STL的常用同类容器中。使用非泛型lambdas的方法是将它们存储在相应的std::function中,该auto non_generic_lambda_1 = [] (int, char) {}; auto non_generic_lambda_2 = [] (int, char) {}; std::vector<std::function<void(int, char)>> vec; vec.push_back(non_generic_lambda_1); vec.push_back(non_generic_lambda_2); 将具有固定的签名调用并且不会限制任何内容,因为你的lambda首先不是通用的,并且只能以这种方式调用:

std::vector<boost::variant>

正如存储部分的第一部分所述,如果您可以限制自己使用给定的固定调用签名,那么您可以对可变参数通用lambda执行相同的操作。

如果你不能,你将需要某种形式的异类容器,如:

  • std::vector<boost::any>
  • boost::fusion::vector
  • {{1}}

有关异类容器的示例,请参阅this question

还有什么?

有关lambda的更多一般信息以及有关生成的成员以及如何在lambda中使用参数的详细信息,请参阅:

答案 2 :(得分:2)

考虑一下

public class tab1report extends Fragment {

    Callback callback;

    public interface Callback {
        void call();
    }

    onAttach(Context context) {
        callback = (Callback) context;
    }

    onStart() {
        // Some code here
        callback.call();
    }

}

public class tab1Background extends Activity implements tab1report.Callback {
    ListView lv;

    lv = (ListView) findViewById(R.id.lv);
    //some code here

    public void getdata() {

        //some code here 
    }

    public void call() {
        getdate();
    }
}

wandbox here)这&#34; print&#34; lambda是:

  • Variadic
  • 递归
  • 通用
  • 快速

看不到任何模板。 (就在下面:))没有看起来像无线电噪音的C ++代码。简单,干净,最重要的是:

  • 易于维护

难怪&#34;感觉就像一种新语言&#34;。