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)
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.
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 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]; });
^
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?