lambda表达式可以用作为类模板参数吗? (注意这是一个与this one非常不同的问题,它询问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;
但我在GCC 4.4和4.6上对此进行了测试,但它并不起作用,显然是因为lambda表达式创建的匿名类型没有默认构造函数。 (我回忆起与boost::bind
类似的问题。)是否有某些原因标准草案不允许这样做,或者我是错的并且允许但是GCC仅仅落后于它们的实施?
答案 0 :(得分:51)
我问你是否可以这样做:
Foo<decltype([]()->void { })> foo;
不,你不能,因为lambda表达式不会出现在未评估的上下文中(例如decltype
和sizeof
等)。
C ++ 0x FDIS,5.1.2 [expr.prim.lambda] p2
lambda表达式的评估导致prvalue临时(12.2)。这个临时称为 闭合对象。 lambda表达式不应出现在未评估的操作数中(第5条)。 [注:A 闭包对象的行为类似于函数对象(20.8).- end note] (强调我的)
您需要首先创建一个特定的lambda,然后在其上使用decltype:
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派生的闭包对象都可以有完全不同的类型,毕竟它们就像 anonymous 一样。
答案 1 :(得分:9)
@Xeo告诉你原因,所以我会给你解决的问题。
通常,您不希望命名闭包,在这种情况下,您可以使用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
,如果更改相等比较,则最好更改哈希以匹配行为。比较相等的对象应具有相同的散列。
答案 2 :(得分:5)
你不能用闭包来做这件事,因为状态不包含在类型中。
如果你的lambda是无状态的(没有捕获),那么你应该没问题。在这种情况下,lambda衰减为普通函数指针,您可以将其用作模板参数而不是某些lambda类型。
gcc不喜欢它。 http://ideone.com/bHM3n
答案 3 :(得分:3)
您完全可以做类似的事情
std::vector
由于c ++ 20允许在未评估的上下文中使用无状态lambda。
答案 4 :(得分:0)
您必须使用运行时抽象类型,如std::function
,或者将类型创建为局部变量或模板化类的一部分。