Lambda expressions as class template parameters

Can lambda expressions be used as class template parameters? (Note that this is a completely different question than this , which asks if there can be a wildcard expression on its own.)

I ask if you can do something like:

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

This would be useful in cases where, for example, the class template has various parameters, such as equal_to or something else, which are usually implemented as single-line functors. For example, suppose I want to create a hash table instance that uses my own match comparison function. I would like to say something like:

 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; 

But I tested this on GCC 4.4 and 4.6, and it does not work, apparently because the anonymous type created by the lambda expression does not have a default constructor. (I recall a similar problem with boost::bind .) Is there any reason why the draft standard does not allow this, or am I mistaken and allowed, but does GCC simply lag behind in their implementation?

+45
c ++ lambda c ++ 11 templates
May 01 '11 at 14:45
source share
4 answers

I ask if you can do something like:

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

No, you cannot, because lambda expressions should not appear in an invaluable context (e.g. decltype and sizeof , among others). C ++ 0x FDIS, 5.1.2 [expr.prim.lambda] p2

Evaluation of a lambda expression leads to a temporary assignment (12.2). This is a temporary name for the closing object. A lambda expression should not appear in an unpublished operand (section 5). [Note: A closure object behaves like a function object (20.8) .- end of note] (emphasis mine)

You will need to create a specific lambda first and then use decltype to do this:

 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; 

This is because each circuit object on a lambda can have a completely different type, they are just like anonymous functions.

+37
May 01 '11 at 15:17
source share

@Xeo gave you a reason, so I will give you a job.

Often you don't want to call a closure, in which case you can use std::function , which is a type:

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

Please note that it accurately captures the signature of the function and no more.

Then you can simply write lambda when building the map.

Note that with unordered_map , if you change the equality comparison, you better change the hash to match the behavior. Objects that compare peers must have the same hash.

+6
May 01 '11 at 15:45
source share

You cannot do this with closure because the state is not contained in the type.

If your lambda is stateless (no seizures), then you should be fine. In this case, the lambda decomposes into a regular function pointer, which you can use as a template argument instead of some lambda type.

gcc he doesn't like it. http://ideone.com/bHM3n

+4
May 01 '11 at 16:00
source share

You will have to use either an abstract runtime type, such as std::function , or create it as a local variable or as part of a template class.

0
May 01 '11 at 15:25
source share



All Articles