type reduction for integer types(sign bits)

69 views
Skip to first unread message

unituni...@gmail.com

unread,
Jun 2, 2013, 5:40:53 AM6/2/13
to std-pr...@isocpp.org
Considering there is an integer type XInt_Type with bitwidth of n:

How about to let the form of
unsigned XInt_Type
be as an unsigned integer type and the form of
signed XInt_Type as an signed integer type?

It's useful if it is used in template.

template < typename _XInt_Ty >
Make_Signed
{
    typedef signed _XInt_Ty type;
};

template < typename _XInt_Ty >
Make_Unsigned
{
    typedef unsigned _XInt_Ty type;
};


class A;

'Make_Signed<signed Int16>::type' is 'signed Int16'
'Make_Signed<unsigned Int64>::type' is 'unsigned Int64'
'Make_Signed<void *>::type' is 'void *' (no effect to Pointers)
'Make_Signed<A>::type' causes compiling error
'Make_Signed<signed char>::type' is always signed.
'Make_Unsigned<signed Int32>::type' is 'unsigned Int32'
'Make_Unsigned<unsigned Int64>::type' is 'unsigned Int64'
'Make_Unsigned<void *>::type' is 'void *' (no effect to Pointers)
'Make_Unsigned<A>::type' causes compiling error
'Make_Unsigned<signed char>::type' is always unsigned.

Let the signed [other signes...] [integer_type] be always the signed integer type and the
signed [other signes...] [integer_type] be always the unsigned integer type.

Such mapping tech that used in BOOST library seems can't cover all the integer types (of the future or compiler extended integer types), comparison to the post at this. Either they weren't brief.

Daniel Krügler

unread,
Jun 2, 2013, 7:50:44 AM6/2/13
to std-pr...@isocpp.org
2013/6/2 <unituni...@gmail.com>:
I assume for the last sentence that you intended to say here:

"unsigned [other signes...] [integer_type] be always the unsigned integer type."

I'm not so happy with that proposal for the following reasons:

a) The unsigned/signed specifiers are not applicable to user-defined
types (like const or volatile), they are also not isolated specifiers,
because they are used to denote a type such as 'unsigned int'. So in
any way the suggested rules only help when applied to built-in types.

b) We have already a library solution for this: std::make_signed and
std::make_unsigned. It is valid for *all* all integer types (including
the extended ones).

c) I also find your suggested rules confusing: Why is
Make_Unsigned<void *>::type well-formed and a no-op, but
Make_Unsigned<A>::type is ill-formed? What is the rationale for that
difference?

> Such mapping tech that used in BOOST library seems can't cover all the
> integer types (of the future or compiler extended integer types), comparison
> to the post at this.

Exactly for this reason the std::make_signed and std::make_unsigned
where introduced. At the moment I see no convincing reasons for a core
language change, especially because I wouldn't see clear consensus on
the effects of applying these specifiers on non-integral types.

- Daniel

unituni...@gmail.com

unread,
Jun 2, 2013, 1:21:59 PM6/2/13
to std-pr...@isocpp.org, unituni...@gmail.com
a) 'the unsigned/signed specifiers are not applicable to user-defined types'
The purpose of these two is still not changed, which is to denote a build-in integer types, then we can just leave this alone, and this kind of proposal is not to target to change it.

b) Actually the make_signed and make unsigned are not valid for *all* integer types. It internally uses a kind of enumerating method, which means that you can't make sure that the same header can work for all compilers:
The file here is snipped from msvc:

// TEMPLATE CLASS make_signed
template<class _Ty>
struct make_signed
{ // signed partner to _Ty
static const size_t _Bytes = sizeof (_Ty);

typedef typename _If<is_signed<_Ty>::value, _Ty,
typename _If<_Bytes <= sizeof (char), signed char,
typename _If<_Bytes <= sizeof (short), short,
typename _If<_Bytes <= sizeof (int), int,
typename _If<_Bytes <= sizeof (long), long,
_Longlong>::_Type>::_Type>::_Type>
::_Type>::_Type type;
};

// TEMPLATE CLASS make_unsigned
template<class _Ty>
struct make_unsigned
{ // unsigned partner to _Ty
static const size_t _Bytes = sizeof (_Ty);

typedef typename _If<is_unsigned<_Ty>::value, _Ty,
typename _If<_Bytes <= sizeof (char), unsigned char,
typename _If<_Bytes <= sizeof (short), unsigned short,
typename _If<_Bytes <= sizeof (int), unsigned int,
typename _If<_Bytes <= sizeof (long), unsigned long,
_ULonglong>::_Type>::_Type>::_Type>
::_Type>::_Type type;
};

Assuming if a kind of integer type like __int128 has been implimented into the compiler as the extended integer types from some day, The make_xsigned templates have to be adjusted too to cover that extension. So that solution is not once-for-all's.

c) Roughly i think that there are several compilers care about the sign bit of the pointers internally and others don't, on the contrary. However it shouldn't have been relied on in well formed C++ sources, so i said 'no effect'.
The two have been ruled forbidden to denote the UDTs currently, so we can just keep on what the rule is for UDTs. If it's necessary, we can forbid signed/unsigned for pointers either.


MY NETWORK IS A CRAP!!!

Martinho Fernandes

unread,
Jun 3, 2013, 7:24:02 AM6/3/13
to std-pr...@isocpp.org, unituni...@gmail.com
On Sun, Jun 2, 2013 at 7:21 PM, <unituni...@gmail.com> wrote:
b) Actually the make_signed and make unsigned are not valid for *all* integer types.

This is from the standard text:

template <class T>
struct make_signed;

If T names a (possibly cv-qualified) signed integer type (3.9.1) then the
member typedef type shall name the type T; otherwise, if T names a
(possibly cv-qualified) unsigned integer type then type shall name the
corresponding signed integer type, with the same cv-qualifiers as T;
otherwise, type shall name the signed integer type with smallest
rank (4.13) for which sizeof(T) == sizeof(type), with the same
cv-qualifiers as T.
Requires:T shall be a (possibly cv-qualified) integral type or enumeration
but not a bool type.

template <class T>
struct make_unsigned;
If T names a (possibly cv-qualified) unsigned integer type (3.9.1) then
the member typedef type shall name the type T; otherwise, if T names a
(possibly cv-qualified) signed integer type then type shall name the
corresponding unsigned integer type, with the same cv-qualifiers as T;
otherwise, type shall name the unsigned integer type with smallest
rank (4.13) for which sizeof(T) == sizeof(type), with the same
cv-qualifiers as T.
Requires:T shall be a (possibly cv-qualified) integral type or enumeration
but not a bool type.

It says so right there that it is valid for *all* integer types.


It internally uses a kind of enumerating method, which means that you can't make sure that the same header can work for all compilers:

Who cares? There are lots of stuff in the standard library that require compiler magic. That was never a problem. Good luck making a particular implementation of is_pod work on all compilers.

Those traits are the primitives. Treat them as such. There is no point in adding another primitive that is the same and whose sole use case is the implementation of the other primitive.

MY NETWORK IS A CRAP!!!
 
Ok.

Mit freundlichen Grüßen,

Martinho

Reply all
Reply to author
Forward
0 new messages