C ++ 1y提供多态lambda(即使用auto
作为参数类型的一部分):
int f(int);
double f(double);
std::string f(const std::string&);
auto funcObj = [](const auto& param){ return f(param); }
存储lambda生成的闭包很容易,如图所示:只需使用auto
变量。但是假设我想要创建vector
个这样的对象。 vector
持有什么类型?通常的答案是使用std::function
,但在这种情况下不起作用,因为AFAIK没有多态std::function
这样的东西,即这在C +中是不合法的+ 1Y:
std::vector<std::function<auto(const auto&)>> vecOfPolymorphicClosures;
如果这是合法的,那么你可以做一些事情,比如创建一个回调容器,每个回调可以用任何一组参数调用,每个参数都可以返回一个依赖于传递的参数类型的类型。任何给定回调的结果都可以存储在auto
变量中,至少在理论上是这样。
两个问题:
boost::any
除外)?答案 0 :(得分:3)
没有。好吧也许吧。
对于您的特定情况,您的lambda只是实例化时已知的单个函数f
的覆盖集。可以创建覆盖集对象并使用类型擦除传递而不会出现太多问题。您只需手动枚举覆盖并将其提供给覆盖集。
因此,如果你的目标只是拥有一个覆盖集f
的对象,是的,你可以这样做。请参阅"Manual" signature overload resolution - 在这个混乱的基础上添加一些类型的擦除,bob是你的叔叔。
一般情况下,你有一些auto
lambda,里面有任意代码,没有。
设想这个问题的方法是想象一个用你的lambda编译的DLL或共享库,第二个DLL或共享库,保存function
类似的对象,以及一些其他想要调用它的DLL或共享库。 / p>
调用function
时发生的行为取决于lambda 的定义和你要用它调用任意程度的类型。
为了使其工作,必须在创建lambda的DLL和调用它的类型的DLL中使用几乎完整的运行时编译模型,并且运行时编译模型将必须兼容。
这不是C ++标准所要求的,如果是这样的话会使事情变得复杂得多,并且会消除优化机会。
现在,并非一切都没有希望。
如果您希望支持某些类型的固定列表,则可以编写多态function
签名。这基本上是上面“覆盖集”解决方案的一个特例,甚至可以用它来编写。
另一方面,如果您愿意键入擦除lambda参数的属性,并键入erase,并返回一些统一类型(无论是boost::any
还是boost::variant
或其他) ,你可以做点什么。您编写了类型擦除对象类型,并将其公开。然后你有一个std::function< boost::any(type_erasure_object) >
,并且转换发生在调用之外,并且在调用中你处理所述类型的擦除对象。
使用类型擦除对象选择重载非常棘手,因为C ++编译器对生成要考虑的重载列表没有多大帮助。如果您手动收集该列表,您甚至可以键入擦除您将选择的过载。
可以将其拉下来,但我之前没有写过。替代方案都容易得多。
我不考虑类型擦除的情况来解决这个问题,因为它会阻止某些类型的优化。但从理论上讲,这意味着你可以使用几乎任意的类型。
类型擦除对象必须暴露给最终用户,并且必须删除 每个 lambda的每个类型信息<{1}}需要知道。因此,在某些情况下,这可以显着限制您在std::vector
中存储的lambda。
有关如何键入擦除几乎任意对象的示例,请查看boost类型擦除。
最后,您要求的内容很少是问题的实际要求。你最好描述你实际的,实际的问题,几乎可以肯定的解决方案并不像上面那样深奥。
答案 1 :(得分:1)
所谓的通用lambda 的类型是具有成员模板operator()
的类类型。当需要转换时,必须知道实际类型。对于非捕获通用lambda,当前的标准草案甚至包含一个示例:
auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;
这与从普通函数模板形成函数指针没什么不同。
对于一般的通用lambda,我认为期望可调用对象的转换会触发正确的模板特化,因此std::function<int(int)> f(glambda);
应该可以正常工作。
答案 2 :(得分:1)
我想要存储的是不同类型的对象,但每个对象都可以使用一组可能无限的参数类型进行调用。
翻译单位A:
// a.cpp
#include <cassert>
std::vector<magical_type> v;
struct lives_in_a { int i; };
// defined in TU B:
void prepare();
int main()
{
prepare();
assert( v.front()(lives_in_a { 42 }) == 42 );
}
翻译单位B:
// b.cpp
struct lives_in_b {
template<typename Anything>
int operator()(Anything const& a) const
{ return a.i; }
};
void prepare()
{
// ignore global initialization order fiasco for the sake
// of the argument
extern std::vector<magical_type> v;
v.push_back(lives_in_b {});
}
lives_in_b::operator()<lives_in_a>
实例化的时间和地点,以便可以调用它?
使用参数v.front()
调用lives_in_a {}
时?在这种情况下,看不到lives_in_b
的定义,甚至没有实例化的定义。
调用v.push_back(lives_in_b {})
时?在那种情况下,看不到lives_in_a
的定义,因此可能实例化的内容并不多。
这是一个演示,C ++的编译模型和模板实例化的方式的特定组合,不允许该特定的愿望。它与静态类型关系不大。