T(2) == T(1) 与对于整数类型 T 的 std::is_same_v 有何不同?

huangapple go评论64阅读模式
英文:

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&lt;typename _Mn, typename _Nn&gt;
    constexpr common_type_t&lt;_Mn, _Nn&gt;
    gcd(_Mn __m, _Nn __n) noexcept
    {
      static_assert(is_integral_v&lt;_Mn&gt;, &quot;std::gcd arguments must be integers&quot;);
      static_assert(is_integral_v&lt;_Nn&gt;, &quot;std::gcd arguments must be integers&quot;);
      static_assert(_Mn(2) != _Mn(1), &quot;std::gcd arguments must not be bool&quot;); // HERE
      static_assert(_Nn(2) != _Nn(1), &quot;std::gcd arguments must not be bool&quot;);
      using _Up = make_unsigned_t&lt;common_type_t&lt;_Mn, _Nn&gt;&gt;;
      return __detail::__gcd(__detail::__absu&lt;_Up&gt;(__m),
			     __detail::__absu&lt;_Up&gt;(__n));
    }

It seems that libstdc++ is intentionally avoiding the more apparent form !is_same_v&lt;_Mn, bool&gt;. 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&lt;remove_cv_t&lt;_Mn&gt;, bool&gt; in libstdc++. (Commit)

答案1

得分: 4

只有一种类型可以通过is_integral_v&lt;_Mn&gt;断言,但会失败于_Mn(1) == _Mn(2)的检查,那就是bool。在这种特殊情况下,只考虑std::integral_v == true的类型,这个检查可以识别bool

请注意,_Mn(1) == _Mn(2)可以检测和bool的cv变体,因此正确的比较应该是std::is_same_v&lt;std::remove_cv_t&lt;Mn&gt;,bool&gt;(感谢Jarod42指出)。

然而,当不仅考虑std::integral_v == true时,_Mn(1) == _Mn(2)的检查不足以知道它是否是bool。它可能是任何其他类型。

当您想知道两种类型是否相同时,应该使用std::is_same

英文:

There is only one type that passes the is_integral_v&lt;_Mn&gt; 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&lt;std::remove_cv_t&lt;Mn&gt;,bool&gt; (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&lt;T&gt; &amp;&amp; !std::is_same_v&lt;T, bool&gt; but fail std::is_integral_v&lt;T&gt; &amp;&amp; T(2) == T(1). std::remove_cv_t&lt;T&gt; should be used instead of T in std::is_same_v to handle these types correctly.

huangapple
  • 本文由 发表于 2023年2月6日 20:19:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75361241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定