英文:
How is T(2) == T(1) different from std::is_same_v<T, bool> for integral types T?
问题
我想确保在static_assert
中,一个整数类型不是bool
。我在libstdc++的源代码中找到了它使用_Mn(2) != _Mn(1)
来实现这一目的:
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
gcd(_Mn __m, _Nn __n) noexcept
{
static_assert(is_integral_v<_Mn>, "std::gcd arguments must be integers");
static_assert(is_integral_v<_Nn>, "std::gcd arguments must be integers");
static_assert(_Mn(2) != _Mn(1), "std::gcd arguments must not be bool"); // HERE
static_assert(_Nn(2) != _Nn(1), "std::gcd arguments must not be bool");
using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
return __detail::__gcd(__detail::__absu<_Up>(__m),
__detail::__absu<_Up>(__n));
}
看起来libstdc++故意避免了更明显的形式!is_same_v<_Mn, bool>
。这两种形式有何不同?我应该在相同的情况下使用哪一个?
@KamilCuk指出,在libstdc++中,_Mn(2) != _Mn(1)
曾经是!is_same_v<remove_cv_t<_Mn>, bool>
。 (提交记录)
英文:
I would like to ensure that an integral type is not bool
in static_assert
. I found in the source code of libstdc++ that it uses _Mn(2) != _Mn(1)
for this purpose:
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
gcd(_Mn __m, _Nn __n) noexcept
{
static_assert(is_integral_v<_Mn>, "std::gcd arguments must be integers");
static_assert(is_integral_v<_Nn>, "std::gcd arguments must be integers");
static_assert(_Mn(2) != _Mn(1), "std::gcd arguments must not be bool"); // HERE
static_assert(_Nn(2) != _Nn(1), "std::gcd arguments must not be bool");
using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
return __detail::__gcd(__detail::__absu<_Up>(__m),
__detail::__absu<_Up>(__n));
}
It seems that libstdc++ is intentionally avoiding the more apparent form !is_same_v<_Mn, bool>
. How are the two forms different? Which one should I use for the same purpose?
@KamilCuk pointed out that _Mn(2) != _Mn(1)
was once !is_same_v<remove_cv_t<_Mn>, bool>
in libstdc++. (Commit)
答案1
得分: 4
只有一种类型可以通过is_integral_v<_Mn>
断言,但会失败于_Mn(1) == _Mn(2)
的检查,那就是bool
。在这种特殊情况下,只考虑std::integral_v == true
的类型,这个检查可以识别bool
。
请注意,_Mn(1) == _Mn(2)
可以检测和bool
的cv变体,因此正确的比较应该是std::is_same_v<std::remove_cv_t<Mn>,bool>
(感谢Jarod42指出)。
然而,当不仅考虑std::integral_v == true
时,_Mn(1) == _Mn(2)
的检查不足以知道它是否是bool
。它可能是任何其他类型。
当您想知道两种类型是否相同时,应该使用std::is_same
。
英文:
There is only one type that passes the is_integral_v<_Mn>
assert but would fail the _Mn(1) == _Mn(2)
check, and that is bool
. The check is ok to identify bool
in this special circumstance, when only types that are std::integral_v == true
are considered.
Note that _Mn(1) == _Mn(2)
can detect and cv variant of bool
, hence the right comparison is std::is_same_v<std::remove_cv_t<Mn>,bool>
(Thanks to Jarod42 to point that out).
However, when not considering only std::integral_v == true
the _Mn(1) == _Mn(2)
check is not sufficient to know that it is bool
or not. It could be any other type.
When you want to know if two types are the same you should use std::is_same
.
PS: In general I do not advise to learn how to write C++ code from the implementation of the standard library. By no means it is bad code, but it is code that lives in a different domain. Most notably, things that are undefined in user code can be completely fine in the implementation (as for example identifiers like _Mn
).
答案2
得分: 1
cv-qualified non-reference bool
types (const bool
, volatile bool
, 和 const volatile bool
) 会通过 std::is_integral_v<T> && !std::is_same_v<T, bool>
,但会失败于 std::is_integral_v<T> && T(2) == T(1)
。在 std::is_same_v
中应该使用 std::remove_cv_t<T>
来正确处理这些类型。
英文:
It turns out that cv-qualified non-reference bool
types (const bool
, volatile bool
and const volatile bool
) pass std::is_integral_v<T> && !std::is_same_v<T, bool>
but fail std::is_integral_v<T> && T(2) == T(1)
. std::remove_cv_t<T>
should be used instead of T
in std::is_same_v
to handle these types correctly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论