如何编写一个通用的相等比较,当 std::cmp_equal 无法编译时,该比较将回退到operator==?

问题描述 投票:0回答:1

我想要一个通用的相等检查函数,由于它的优点,它在可能的情况下更喜欢使用 std::cmp_equal,但对于 std::cmp_equal 无法处理的类型(例如 bool 或用户定义类型)将使用运算符== .

对于

requires
来说,这似乎是一项简单的工作,但我惊讶地发现,虽然这适用于 libc++,但对于带有 static_assert 消息的 libstdc++ 却失败了。

#include <utility>

template <typename T, typename U>
auto generic_equal(T t, U u) {
    if constexpr (requires { std::cmp_equal(t, u); }) {
        return std::cmp_equal(t, u);
    } else {
        return t == u;
    }
}

struct A {
    friend bool operator==(A,A) = default;
};

int main() {
    generic_equal(false, false);
    generic_equal(-1, 5);
    generic_equal(A{}, A{});
}

有没有一种好方法可以说服编译器认识到它无法在

requires
而不是在调用时实例化 std::cmp_equal ?

编译器资源管理器链接显示 libc++ 成功,libstdc++ 失败:https://godbolt.org/z/nKzfE87Ye

c++ operator-overloading c++20 customization-point
1个回答
2
投票

std::cmp_equal
要求模板参数必须是标准整数类型扩展整数类型,其定义在[basic.fundamental]:

  1. 有五种标准有符号整数类型:“

    signed char
    ”、“
    short int
    ”、“
    int
    ”、“
    long int
    ”和“
    long long int
    ”。在此列表中,每种类型至少提供与其前面的列表一样多的存储空间。 还可能存在实现定义的扩展有符号整数类型。 [...]

  2. 对于每个标准有符号整数类型,都存在一个 对应(但不同)标准无符号整数类型: “

    unsigned char
    ”、“
    unsigned short int
    ”、“
    unsigned int
    ”、 “
    unsigned long int
    ”和“
    unsigned long long int
    ”。同样,对于 每个扩展有符号整数类型,都存在一个 对应的扩展无符号整数类型。 [...]

由于它不是受约束的函数,因此当传递非标准整数类型时,它仍然会被实例化并命中内部可能的静态断言。您可以通过检测

std::cmp_equal
是否为
标准整数类型
来决定是否使用T进行比较:

#include <utility>
#include <concepts>

template <typename T>
concept standard_integral = 
  std::integral<T> &&
  !std::same_as<T, char> &&
  !std::same_as<T, char8_t> &&
  !std::same_as<T, char16_t> &&
  !std::same_as<T, char32_t> &&
  !std::same_as<T, wchar_t> &&
  !std::same_as<T, bool>;

template <typename T, std::equality_comparable_with<T> U>
bool generic_equal(T t, U u) {
    if constexpr (standard_integral<T> && standard_integral<U>) {
        return std::cmp_equal(t, u);
    } else {
        return t == u;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.