作为类模板参数的 Lambda 表达式

Lambda 表达式可以使用 作为类模板参数吗?(注意,这是一个与 这个非常不同的问题,这个询问是否可以模板化 lambda 表达式本身。)

我是问你能不能做一些像这样的事情:

template <class Functor>
struct Foo { };
// ...
Foo<decltype([]()->void { })> foo;

例如,在类模板具有诸如 equal_to之类的各种参数的情况下,这将非常有用,这些参数通常作为一行函数实现。例如,假设我想实例化一个哈希表,它使用我自己的自定义相等比较函数。我想说的是:

typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
decltype([](const std::string& s1, const std::string& s2)->bool
{ /* Custom implementation of equal_to */ })
> map_type;

但是我在 gcc4.4和4.6上测试了一下,显然没有用,因为 lambda 表达式创建的匿名类型没有缺省构造函数。(我记得 boost::bind也有类似的问题。)标准草案不允许这样做是否有某种原因,或者我错了,它是允许的,但海湾合作委员会只是落后于他们的实施?

48170 次浏览

从 C + + 20开始,这个答案已经过时了。 C + + 20在未评估的上下文中引入了无状态的 lambdas。 1:

这个限制最初是为了防止 lambdas 出现在签名中,因为 lambdas 必须具有唯一的类型,这会打开一个蠕虫的罐头。然而,这种限制比它所需要的要强烈得多,没有这种限制确实有可能达到同样的效果

一些限制仍然存在(例如 lambdas 仍然不能出现在函数签名上) ,但是描述的用例现在完全有效,不再需要声明变量。


我是问你能不能做一些像这样的事情:

Foo<decltype([]()->void { })> foo;

不可以,因为 lambda 表达式不能出现在未计算的上下文中(比如 decltypesizeof等等)。 C + + 0x FDIS,5.1.2[ expr.prim.lambda ] p2

对 lambda 表达式的计算会产生一个 prvalue 临时值(12.2) 关闭对象。 未计算操作数中不应出现 lambda 表达式(第5条) 闭包对象的行为类似于函数对象(20.8) (强调我的)

您需要首先创建一个特定的 lambda,然后在其上使用 dectype:

auto my_comp = [](const std::string& left, const std::string& right) -> bool {
// whatever
}


typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
decltype(my_comp)
> map_type;

这是因为每个派生自 lambda 的闭包对象可以具有完全不同的类型,它们毕竟类似于 匿名的函数。

您必须使用运行时抽象类型(如 std::function) ,或者将该类型创建为局部变量或模板类的一部分。

@ 希欧给了你理由,所以我会给你工作。

通常您不希望命名闭包,在这种情况下,您可以使用 std::function,它是一种类型:

typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
std::function<bool(std::string const&, std::string const&)>
> map_type;

注意,它只捕获函数的签名,仅此而已。

然后,您可以在构建映射时简单地编写 lambda。

请注意,对于 unordered_map,如果更改相等性比较,则最好更改散列以匹配行为。比较相等的对象应具有相同的散列。

不能对闭包执行此操作,因为状态不包含在类型中。

如果您的 lambda 是无状态的(没有捕获) ,那么应该没问题。在这种情况下,lambda 衰减为一个普通的函数指针,你可以用它作为一个模板参数,而不是一些 lambda 类型。

但是 GCC 不喜欢这样 http://ideone.com/bHM3n

C + + 20回答: 是的!

你完全可以这么做

Foo<decltype([]()->void { })> foo;

因为 c + + 20允许在未计算上下文中使用无状态 lambdas。