Skip to content

flat_map.equal_range hard error when Compare is not a std::relation #44

@Quuxplusone

Description

@Quuxplusone

https://godbolt.org/z/jTGz5sTPP

#include <cassert>
#include <flat_map>
#include <string>

struct StartsWith {
  explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch+1) {}
  struct Less {
    using is_transparent = void;
    bool operator()(const std::string& a, const std::string& b) const { return a < b; }
    bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; }
    bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; }
    //bool operator()(const StartsWith& a, const StartsWith& b) const;
  };
private:
  std::string lower_;
  std::string upper_;
};

int main() {
  using M = std::flat_map<std::string, int, StartsWith::Less>;
  M m = { {"alpha", 1}, {"beta", 2}, {"epsilon", 3}, {"eta", 4}, {"gamma", 5} };
  auto begin = m.begin();
  assert(m.equal_range(StartsWith('b')) == std::pair(begin+1, begin+2));
}

libc++ trunk complains:

__flat_map/flat_map.h:1035:19: error: no matching function for call to object of type 'const __lower_bound'
 1035 |     auto __it   = ranges::lower_bound(__self.__containers_.keys, __key, __self.__compare_);
      |                   ^~~~~~~~~~~~~~~~~~~

Ultimately because:

__concepts/invocable.h:34:29: note: because 'invocable<StartsWith::Less &, StartsWith &, StartsWith &>' evaluated to false
   34 | concept regular_invocable = invocable<_Fn, _Args...>;
      |                             ^

But [associative.reqmts] doesn't seem to require that any value c of type X::key_compare should model std::regular_invocable — it requires merely that expressions such as c(x, kx) and c(kx, x) should be well-formed, and that c should induce a strict weak ordering.

Uncommenting the member function operator()(const StartsWith& a, const StartsWith& b) above makes the test compile; but that shouldn't be necessary, as flat_map never has any reason to compare one StartsWith object against another.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions