Skip to content

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

@sfreilich

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions