1

I am trying to define a type that's an unordered_set over pairs of unsigned int:

typedef std::pair<unsigned int, unsigned int> Loc;
auto HashLoc = [](const Loc &l) {
  return l.first << 16 ^ l.second;
};
typedef std::unordered_set<Loc, decltype(HashLoc)> LocSet;

This was based on the accepted answer to creating unordered_set with lambda.

I'm getting an error, error: call to implicitly-deleted default constructor of 'LocSet', when I try to actually declare an object of that type. Based on the extra detail the compiler gives, it looks like it's trying to call a deleted default constructor for the lambda.

Interestingly, the answer linked to above suggests that VS2013 does just this and it's a bug, but gcc and clang are supposed to work. But, I'm using clang (version 8.0.1). Is this expected behavior, and if so, what's the proper way to do what I'm trying to do?

Dominick Pastore
  • 4,177
  • 2
  • 17
  • 29

1 Answers1

2

You need to compile with C++20 mode, i.e. with the option -std=c++2a.

Before C++20 lambda closure types have no default constructor.

Closure types are not DefaultConstructible. Closure types have no default constructor (until C++20)

If no captures are specified, the closure type has a defaulted default constructor. (since C++20)

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Hmm. The C++ standard version isn't something that's in my control. Surely there's some other workaround before C++20? – Dominick Pastore Sep 26 '20 at 05:24
  • Using a wrapper? `struct HashLocWrapper { size_t operator()(const Loc &l) { return HashLoc(l); } };` – MikeCAT Sep 26 '20 at 05:28
  • 1
    @DominickPastore You can pass `HashLoc` to the constructor of `std::unordered_set` to avoid default-construction of the lambda closure type, or use user-defined class instead of lambda. – songyuanyao Sep 26 '20 at 05:29
  • Thanks. I wonder why there is so much conflicting information on this. I've found several sources saying to do it the way I originally had it, many predating C++20 (including the question I linked to). There's even a [2013 blog post on isocpp.org itself](https://isocpp.org/blog/2013/04/quick-q-how-can-use-a-lambda-function-as-a-hash-function-for-unordered-map) saying to do it this way. – Dominick Pastore Sep 26 '20 at 05:39
  • @DominickPastore, that post links to an [answer](https://stackoverflow.com/a/15719698) where a lambda is passed as an argument to the constructor. – Evg Sep 26 '20 at 06:28
  • @Evg It does, but the contents of the post itself only say to name the lambda and `decltype` it. Reading it again, that's not really "conflicting," just incomplete. (It seems that this is what most of the sources I thought were conflicting do: They do pass the lambda to the constructor in their examples, but almost none of them mention it, focusing only on the template parameters, so I never noticed that step.) – Dominick Pastore Sep 26 '20 at 15:24