我想确保整型不是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指出,_Mn(2) != _Mn(1)
在libstdc中曾经是!is_same_v<remove_cv_t<_Mn>, bool>
.(Commit)
2条答案
按热度按时间jobtbby31#
只有一种类型通过
is_integral_v<_Mn>
Assert,但_Mn(1) == _Mn(2)
检查失败,这就是bool
。在这种特殊情况下,当只考虑std::integral_v == true
类型时,检查可以识别bool
。注意
_Mn(1) == _Mn(2)
可以检测和cvbool
的变体,因此正确的比较是std::is_same_v<std::remove_cv_t<Mn>,bool>
(感谢Jarod42指出这一点)。然而,当不考虑仅
std::integral_v == true
时,_Mn(1) == _Mn(2)
检查不足以知道它是否是bool
,它可以是任何其他类型。当你想知道两个类型是否相同时,你应该使用
std::is_same
。PS:一般来说,我不建议从标准库的实现中学习如何编写C++代码。这绝不是糟糕的代码,而是生活在不同领域中的代码。最值得注意的是,用户代码中未定义的东西在实现中可能完全没有问题(例如
_Mn
这样的标识符)。vktxenjb2#
事实证明,cv限定的非引用
bool
类型(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::remove_cv_t<T>
而不是std::is_same_v
中的T
来正确处理这些类型。