我想要一个通用的相等检查函数,由于它的优点,它在可能的情况下更喜欢使用 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
std::cmp_equal
要求模板参数必须是标准整数类型或扩展整数类型,其定义在[basic.fundamental]:
有五种标准有符号整数类型:“
”、“signed char
”、“short int
”、“int
”和“long int
”。在此列表中,每种类型至少提供与其前面的列表一样多的存储空间。 还可能存在实现定义的扩展有符号整数类型。 [...]long long int
对于每个标准有符号整数类型,都存在一个 对应(但不同)标准无符号整数类型: “
”、“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;
}
}