【发布时间】:2015-07-08 06:39:07
【问题描述】:
当我将 lambda 分配给显式类型的变量时(例如,当它是递归时,以捕获函数本身),我使用 std::function。
以这个愚蠢的“位计数”函数为例:
std::function<int(int)> f;
f = [&f](int x){ return x ? f(x/2)+1 : 0; };
如果我们使用自动参数来泛化x,就像在 C++14 泛型 lambda 中介绍的那样,情况如何?
std::function<int(???)> f;
f = [&f](auto x){ return x ? f(x/2)+1 : 0; };
显然,我不能将auto 放在function 类型参数中。
是否有可能定义一个足够通用的仿函数类以涵盖上述确切情况,但仍使用 lambda 进行函数定义?
(不要过度概括,只接受一个自动参数并对返回值进行硬编码。)用例将适用于上述场景:通过引用捕获函数本身以进行递归调用。
【问题讨论】:
-
我认为这里的问题是,lamba 函数需要一个确定的类型——
auto只是让编译自己解决。这并不意味着您可以将 lambda 函数传递给其中具有任何类型的任何代码 - 需要在 lambda 函数的编译时知道该类型。 -
auto& f = [&f](auto x){return x ? f(x/2)+1 : 0;};怎么样?那样有用吗? (可能只是auto而不是auto&。)我手边没有支持 C++14 的编译器,所以我不能轻易测试它。 -
std::function使用类型擦除。我相当确定根本不可能编写一个接受任意类型的类型擦除函数对象包装器,因为每组参数类型都需要创建一个新函数,只有当编译器可以看到包装的函数模板时才能做到这一点。解决方法包括使用一组固定的参数类型集(使用现有的重载集/在类型擦除之前预先计算所有重载),或类型擦除参数。 -
@dyp 您可以在参数类型或函数上创建类型擦除,但是在两者上都这样做是难以处理的没有将您的函数(如 boost phoenix)反映到数据中(基本上,在参数类型上重新编译你的函数)。举个具体的例子,想象一下用你的二进制文件发送 gcc,将函数存储为字符串。当传递参数时,您确定它们的类型,打印出该类型的函数,编译动态库,加载它并运行函数。并非完全不可能。并且需要将函数定义为简单的 C++ 代码以外的内容。
-
@dyp 是的。如果你使用 OpenCL 之类的东西,你的内核就是你在运行时编译的字符串。您可以在运行时使用“类型信息”输入来操作所述内核,生成一组无限可能的内核实现中的一个,编译它,然后调用它。当然,除了非常简单的情况外,安全地执行此操作非常困难,这是 C++ 样式模板元编程优于基于字符串的元编程的优势之一。
标签: c++ lambda c++14 auto generic-lambda