Skip to content

Build fails under clang-cl with C++20 #35

Description

@sfreilich

On a Windows build using clang-cl, the build of //riegeli/records/record_reader fails with:

external/riegeli+/riegeli/records/record_reader.cc(651,9): error: call to 'BinarySearch' is ambiguous
  651 |         BinarySearch(
      |         ^~~~~~~~~~~~
external/riegeli+\riegeli/base/binary_search.h(375,26): note: candidate function [with Pos = unsigned long long, Test = (lambda at external/riegeli+/riegeli/records/record_reader.cc:653:13), $2 = 0]
  375 | inline SearchResult<Pos> BinarySearch(Pos low, Pos high, Test&& test) {
      |                          ^
external/riegeli+\riegeli/base/binary_search.h(454,41): note: candidate function [with Pos = unsigned long long, Test = (lambda at external/riegeli+/riegeli/records/record_reader.cc:653:13), $2 = 0]
  454 | inline std::optional<SearchResult<Pos>> BinarySearch(Pos low, Pos high,
      |                                         ^

The call in question is here:

It has the signature:

BinarySearch(uint64_t, uint64_t, std::optional<PartialOrdering>(uint64_t record_index));

But the compiler thinks it matches the plain overload:

template <
typename Pos, typename Test,
std::enable_if_t<binary_search_internal::TestReturnsOrderingOrSearchGuide<
Test, Pos>::value,
int>>
inline SearchResult<Pos> BinarySearch(Pos low, Pos high, Test&& test) {

As well as the std::optional one:

template <typename Pos, typename Test,
std::enable_if_t<
binary_search_internal::TestReturnsOptionalOrderingOrSearchGuide<
Test, Pos>::value,
int>>
inline std::optional<SearchResult<Pos>> BinarySearch(Pos low, Pos high,
Test&& test) {

It should match the latter, the test returns std::optional<PartialOrdering>, and that should match if PartialOrdering satisfies IsOrdering, which is defined as:

template <typename T, typename Enable = void>
struct IsOrdering : std::false_type {};
template <typename T>
struct IsOrdering<T, std::void_t<decltype(std::declval<T>() < 0),
decltype(std::declval<T>() > 0),
decltype(std::declval<T>() == 0)>>
: std::true_type {};

So it should match if all of <, >, and == are defined when the other arg is 0. But if that applies to T, shouldn't it also apply to std::optional<T>? It does seem like the way those comparison operators are derived differs in C++20, the other comparison operators for std::optional are derived from <=> starting in C++20. But I'm still very confused why the error is only coming up with clang-cl on Windows and not Clang on other platforms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions