Passing lambda as a template parameter not working correctly.

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
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
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
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?
Lambdas don't have default constructors.
Never mind, looks like I missed a template parameter for the 2nd example.

Thanks
#1 is still returning a reference to an expired temporary
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.
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
No, the expired temporary is the value you are returning. The lambda stays valid.
Last edited on
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
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
Oh, I see that warnings weren't enabled. Thanks.
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.