Сравните std :: variant с int, используя C ++ 20 <=> не является постоянным выражением - PullRequest
8 голосов
/ 06 августа 2020

Поскольку std::variant не разрешено сравнивать с одним из его альтернативных типов в стандартной библиотеке, я реализую функцию сравнения с помощью оператора C ++ 20 <=>:

template <typename... Args, typename T>
constexpr auto operator<=>(const std::variant<Args...>& v, const T& t) {
  return std::visit([&t](const auto& u) -> std::partial_ordering {
    if constexpr (requires { u <=> t; }) return u <=> t;
    else return std::partial_ordering::unordered;
  }, v);
}

Но когда я тестирую указанную выше функцию с моей собственной std::variant:

using Variant = std::variant<double, int, std::string_view>;
constexpr Variant v1{1.0};
constexpr Variant v2{1};
constexpr Variant v3{"hello"};
static_assert(v1 < 2);
// compile error
static_assert(v2 < 2);
static_assert(!(v3 > 2) && !(v3 < 2) && !std::is_eq(v3 <=> 2));

Второе утверждение не может скомпилировать , G CC говорит:

<source>:19:17: error: non-constant condition for static assertion
   19 |   static_assert(v2 < 2);
      |                 ^~~~~~~~~
<source>:19:24:   in 'constexpr' expansion of 'operator<=><double, int, std::basic_string_view<char, std::char_traits<char> >, int>(v2, 2)'
<source>:19:17: error: '<anonymous>' is not a constant expression

Почему v2 < 2 не является постоянным выражением? или это просто ошибка G CC ? Что еще более странно, когда я меняю второе утверждение для сравнения с double, оно может компилироваться:

static_assert(v2 < 2.0);

Обновление:

Clang может передать три утверждения, но MSV C может передать только третье утверждение , кажется, что MSV C также содержит ошибку.

1 Ответ

4 голосов
/ 06 августа 2020

Первый пример сводится к:

#include <compare>

// this one is okay
static_assert(std::partial_ordering(std::strong_ordering::less) < 0);

// this one fails with non-constant condition
static_assert(std::partial_ordering(1 <=> 2) < 0);

Очевидно, что все здесь является постоянным выражением. Тот факт, что strong_ordering::less можно легко преобразовать в partial_ordering::less, а 1 <=> 2 не может (на g cc), предполагает, что это ошибка компилятора, а не библиотеки.

...