Is std::is_unsigned<bool>::value well defined?
Solution 1:
There is no concept of signedness for bool
. From [basic.fundamental]/6:
Values of type
bool
are eithertrue
offalse
. [Note: There are nosigned
,unsigned
,short
, orlong
bool
types or values. — end note] Values of typebool
participate in integral promotions (4.5).
By contrast, signedness is explicitly called out for the signed integer types (paragraph 2) and unsigned integer types (paragraph 3).
Now for the is_signed
and is_unsigned
traits. First off, the traits are always well-defined, but only interesting for arithmetic types. bool
is an arithmetic type, and is_signed<T>::value
is defined (see Table 49) as T(-1) < T(0)
. By using the rules of boolean conversion and standard arithmetic conversions, we see that this is is false
for T = bool
(because bool(-1)
is true
, which converts to 1
). Similarly, is_unsigned<T>::value
is defined as T(0) < T(-1)
, which is true
for T = bool
.
Solution 2:
is_unsigned
is defined in [meta.unary.comp]/2 as
If
is_arithmetic<T>::value
istrue
, the same result asbool_constant<T(0) < T(-1)>::value
; otherwise,false
bool
† is clearly an arithmetic type (being integral). Now consider [conv.bool]/1:
A zero value, null pointer value, or null member pointer value is converted to
false
; any other value is converted totrue
.
I.e. bool(0) < bool(-1)
is equivalent to false < true
, and the latter holds since the values are promoted to 0
and 1
, respectively.
Thus is_unsigned<bool>::value
is true
(and, conversely, is_signed
is false
), due to the fact that bool
ean values correspond to the unsigned values 0
and 1
during arithmetic operations. However, it doesn't really make sense to assess bool
's signedness, much less perform make_unsigned
on it, since it doesn't represent integers, but rather states.
†: The fact that this template is applicable to
bool
in the first place is determined by its Requirement clause being non-existent, bool
not being an incomplete type ([res.on.functions]/(2.5)) and no other requirements being mentioned in [meta.rqmts] for UnaryTypeTraits.
Solution 3:
Yes, it is well-defined, as is any other unary type trait.
C++14 (n4140) 20.10.4/2 "Unary type traits" mandates:
Each of these templates shall be a UnaryTypeTrait (20.10.1) with a BaseCharacteristic of
true_type
if the corresponding condition is true, otherwisefalse_type
.
20.10.1/1:
A UnaryTypeTrait describes a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the property being described. It shall be
DefaultConstructible
,CopyConstructible
, and publicly and unambiguously derived, directly or indirectly, from its BaseCharacteristic, which is a specialization of the templateintegral_constant
(20.10.3), with the arguments to the templateintegral_constant
determined by the requirements for the particular property being described. The member names of the BaseCharacteristic shall not be hidden and shall be unambiguously available in the UnaryTypeTrait.
From this it follows that the construct std::is_unsigned<T>::value
has to be well-defined for any type T
, whether the concept of "signedness" makes sense for the type or not.
Solution 4:
Yes it is well defined and the result should be std::is_unsigned<bool>::value == true
The documentation for std::is_signed
says
If
T
is a signed arithmetic type, provides the member constant value equal true. For any other type, value is false.
So then if you look at std::is_arithmetic
If T is an arithmetic type (that is, an integral type or a floating-point type), provides the member constant value equal true. For any other type, value is false.
Which finally leads to std::is_integral
Checks whether T is an integral type. Provides the member constant value which is equal to true, if T is the type
bool
,char
,char16_t
,char32_t
,wchar_t
,short
,int
,long
,long long
, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants. Otherwise, value is equal to false.
Interestingly, there is another function std::numeric_limits::is_signed
that states
The value of
std::numeric_limits<T>::is_signed
istrue
for all signed arithmetic typesT
andfalse
for the unsigned types. This constant is meaningful for all specializations.
Where the specialization for bool
is listed as false
, which also confirms that bool
is considered unsigned.