使用C++20将std::variant与int进行比较<=>不是常量表达式

8

由于标准库中不允许使用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));

第二个断言无法编译,GCC 发出如下消息:

<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 不是一个常量表达式?或者这只是一个 GCC bug ?更奇怪的是,当我将第二个断言改为与 double 比较时,它可以编译通过:
static_assert(v2 < 2.0);

更新:

Clang可以通过三个断言,但是MSVC只能通过第三个断言看起来MSVC也存在一个错误。


1
第一个例子是编译器的错误。第二个例子是不规范的(您的“visit”lambda为不同的调用返回不同的类型),尽管仍然是gcc的错误,导致了内部编译器错误(ICE始终是一个错误)。 - Barry
1个回答

4
第一个例子化简为:
#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(在gcc上)不能被转换,这表明这是编译器而不是库中的错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接