Passing lambda as a template parameter not working correctly.

May 30, 2013 at 7:30pm
I've was trying out a function template to automatically get the type of a lambda, but it seems that it won't compile

I've tried two different ways:

1.
1
2
3
4
5
6
7
template<class HASHER> 
auto make_unordered_map(size_t bucketCount, HASHER const && hf)
  -> unordered_map<string const, HASHER>&&
{
    return unordered_map<string const, int, HASHER>(bucketCount, hf);
}
auto x = make_unordered_map(1, [](string const& key)->size_t { return key[0]; });


2.
1
2
3
4
5
6
7
template<class HASHER> 
auto make_unordered_map(size_t bucketCount, HASHER const && hf2)
  -> unordered_map<string const, int, decltype(hf2)>
{
    return unordered_map<string const, int, decltype(hf2)>(bucketCount, hf2);
}
auto x = make_unordered_map(1, [](string const& key)->size_t { return key[0]; });


The test code are located here:

1. http://ideone.com/62heUn
2. http://ideone.com/BJ8bY3

They are both based on the code that is stated to work in those examples. I.e.:
1
2
auto hf = [](string const& key)->size_t { return key[0]; };
unordered_map<string const, int, decltype(hf)> m (1, hf);


Any idea why wouldn't this work properly?


Adrian
Last edited on May 30, 2013 at 7:45pm
May 30, 2013 at 7:50pm
Even though the lambda expressions are identical, the types of the objects they produce are different. -- not the problem here

Rvalue references to const are never a good idea, and definitely don't work here. Just take HASHER by value. Then your #2 will work (#1 has two more errors: missing int in the return type, and returning a reference to a temporary)
Last edited on May 30, 2013 at 7:59pm
May 30, 2013 at 8:01pm
Use the scroll, Luke!

https://gist.github.com/LB--/5680681

It's giving you a "cannot convert var from T1 to T2" error.
Last edited on May 30, 2013 at 8:06pm
May 30, 2013 at 8:06pm
IIRC, if HASHER is a lambda then it won't have a copy constructor. But changing it from a r-value ref to a l-value ref fixed the problem in way 2. However, this failed to work in way 1.

Code has been updated. Ideas?
May 30, 2013 at 8:09pm
Lambdas don't have default constructors.
May 30, 2013 at 8:12pm
Never mind, looks like I missed a template parameter for the 2nd example.

Thanks
May 30, 2013 at 8:15pm
#1 is still returning a reference to an expired temporary
May 30, 2013 at 8:39pm
I know you're trying to return with move semantics, but you need to just return by value and let copy elision kick in - the compiler will elide the copy for you or it will use the move constructor for you.
May 30, 2013 at 8:40pm
Hmmmmm, that's interesting. Are you are referring to the return value of type unordered_map<string const, int, HASHER const &>&& Cubbi? And the expired temporary would be the object of type HASHER const &?

Not exactly sure if that's true, but it does look like it, doesn't it? I *think*, since the HASHER object has no state, and since a lambda function is not generated on the fly but at compile time... I THINK this is valid.

The compiler seems to have no problem with it.
Last edited on May 30, 2013 at 8:41pm
May 30, 2013 at 8:44pm
No, the expired temporary is the value you are returning. The lambda stays valid.
Last edited on May 30, 2013 at 8:45pm
May 30, 2013 at 8:48pm
The compiler seems to have no problem with it.

The compiler doesn't have to diagnose undefined behavior, but gcc does, with warnings enabled:

test.cc: In instantiation of 'std::unordered_map<const std::basic_string<char>, int, const HASHER&>&& make_unordered_map(size_t, const HASHER&) [with HASHER = <lambda(const string&)>; size_t = long unsigned int]':
test.cc:18:80:   required from here
test.cc:16:76: warning: returning reference to temporary [enabled by default]


and so does clang:

test.cc:16:12: warning: returning reference to local temporary object [-Wreturn-stack-address]
    return unordered_map<string const, int, HASHER const &>(bucketCount, hf);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cc:18:10: note: in instantiation of function template specialization 'make_unordered_map<<lambda at
      test.cc:18:32> >' requested here
auto x = make_unordered_map(1, [](string const& key)->size_t { return key[0]; });
         ^
Last edited on May 30, 2013 at 8:49pm
May 30, 2013 at 8:49pm
I see. As the reference is to a temporary, this is a problem. But why did the compiler not flag this then? I guess the compiler recognises what this is supposed to mean?
Last edited on May 30, 2013 at 8:50pm
May 30, 2013 at 8:51pm
Oh, I see that warnings weren't enabled. Thanks.
May 30, 2013 at 8:55pm
The compiler doesn't have to diagnose undefined behavior


That's funny and sad and annoying. Undefined behaviour should be flagged as this is just as bad if not worse then an error.
Topic archived. No new replies allowed.