What header should int_t go to?

266 views
Skip to first unread message

Myriachan

unread,
Sep 6, 2016, 1:37:22 PM9/6/16
to ISO C++ Standard - Future Proposals
I wanted to write a formal proposal for the std::int_t<BITS> idea that I (and others came up with before me), but I don't know a few things.

For those who didn't see it before, std::int_t<BITS> and related templates (such as std::uint_fast_t<BITS>) are aliases for std::intBITS_t, so that metaprogramming can select an integer type from the bit count.

First, which header should get this template?  It most naturally fits in <cstdint>, but that breaks the paradigm of <cwhatever> only having what is in <whatever.h> from C.  <cinttypes> similarly.  <limits> would work, but seems awkward.

Second, what is the formal wording for something like "the specialization shall not exist"?  I would think something like "int_t<B> shall be an alias for intB_t, if it exists, or shall fail to substitute".

Melissa

Ville Voutilainen

unread,
Sep 6, 2016, 2:27:01 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 20:37, Myriachan <myri...@gmail.com> wrote:
> I wanted to write a formal proposal for the std::int_t<BITS> idea that I
> (and others came up with before me), but I don't know a few things.
>
> For those who didn't see it before, std::int_t<BITS> and related templates
> (such as std::uint_fast_t<BITS>) are aliases for std::intBITS_t, so that
> metaprogramming can select an integer type from the bit count.
>
> First, which header should get this template? It most naturally fits in
> <cstdint>, but that breaks the paradigm of <cwhatever> only having what is
> in <whatever.h> from C. <cinttypes> similarly. <limits> would work, but
> seems awkward.

I actually wouldn't find it horrible to put that stuff into <type_traits>.

> Second, what is the formal wording for something like "the specialization
> shall not exist"? I would think something like "int_t<B> shall be an alias
> for intB_t, if it exists, or shall fail to substitute".


"int_t<B> is an alias for intB_t if the implementation provides the
type intB_t, otherwise
a program that uses the specialization int_t<B> is ill-formed."? I
don't know whether we really
say something like that elsewhere, I just pulled that out of my hat.

Tony V E

unread,
Sep 6, 2016, 3:03:32 PM9/6/16
to ISO C++ Standard - Future Proposals
I'm not sure whether  'uses the specialization' means SFINAE or not. 

I think the request is for wording that means you can sfinae on int_t<N>.




Sent from my BlackBerry portable Babbage Device
  Original Message  
From: Ville Voutilainen
Sent: Tuesday, September 6, 2016 2:26 PM
To: ISO C++ Standard - Future Proposals
Reply To: std-pr...@isocpp.org
Subject: Re: [std-proposals] What header should int_t go to?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbgQrdzqUyUyEV94MwvEyBgm3yDuKeQoMuKKaPE7JkP9Q%40mail.gmail.com.

Ville Voutilainen

unread,
Sep 6, 2016, 3:32:36 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 22:03, Tony V E <tvan...@gmail.com> wrote:
> I'm not sure whether 'uses the specialization' means SFINAE or not.
> I think the request is for wording that means you can sfinae on int_t<N>.

I am unaware of a way to sfinae on mentioning a specialization. I know how
to sfinae on expressions that use the type. As in
http://cplusplus.github.io/LWG/lwg-active.html#2543

Ville Voutilainen

unread,
Sep 6, 2016, 4:18:46 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 22:32, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> I am unaware of a way to sfinae on mentioning a specialization. I know how
> to sfinae on expressions that use the type. As in
> http://cplusplus.github.io/LWG/lwg-active.html#2543

Well, ok, I am actually aware of such a way, given a good enough C++
compiler that implements
a certain Technical Specification:


#include <type_traits>
#include <iostream>

template <class T> requires !std::is_integral_v<T>
struct Wrap
{
Wrap() = default;
};

template <class T> void f(const T&, const Wrap<T>* = 0)
{
std::cout << "wrap" << std::endl;
}


template <class T> void f(...)
{
std::cout << "T" << std::endl;
}

int main()
{
int x = 42;
double y = 0.666;
f<int>(x);
f<double>(y);
}

The code prints

T
wrap

http://melpon.org/wandbox/permlink/zMgN7xgCmDQHwN6a

Ville Voutilainen

unread,
Sep 6, 2016, 4:24:43 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 23:18, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> On 6 September 2016 at 22:32, Ville Voutilainen
> <ville.vo...@gmail.com> wrote:
>> I am unaware of a way to sfinae on mentioning a specialization. I know how
>> to sfinae on expressions that use the type. As in
>> http://cplusplus.github.io/LWG/lwg-active.html#2543
>
> Well, ok, I am actually aware of such a way, given a good enough C++
> compiler that implements
> a certain Technical Specification:


A much simpler example (note that without the constraint, the code
would call the wrap-case for both
calls).

#include <type_traits>
#include <iostream>

template <class T> requires !std::is_integral_v<T>
struct Wrap;

template <class T> void f(const T&, const Wrap<T>* = 0)
{
std::cout << "wrap" << std::endl;
}


void f(...)
{
std::cout << "T" << std::endl;
}

int main()
{
int x = 42;
double y = 0.666;
f(x);
f(y);
}

http://melpon.org/wandbox/permlink/j7AH29tKoUAO7ndv

Myriachan

unread,
Sep 6, 2016, 4:42:39 PM9/6/16
to ISO C++ Standard - Future Proposals
On Tuesday, September 6, 2016 at 1:24:43 PM UTC-7, Ville Voutilainen wrote:
>> I am unaware of a way to sfinae on mentioning a specialization. I know how
>> to sfinae on expressions that use the type. As in
>> http://cplusplus.github.io/LWG/lwg-active.html#2543


I mean substitution failure for SFINAE along these lines, where the output is "1 2 99 4":

#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <type_traits>

namespace meow  //std
{
   
template <int B>
   
struct _int_t_helper;

   
template <> struct _int_t_helper<8> { typedef std::int8_t type; };
   
template <> struct _int_t_helper<16> { typedef std::int16_t type; };
   
template <> struct _int_t_helper<32> { typedef std::int32_t type; };
   
template <> struct _int_t_helper<64> { typedef std::int64_t type; };

   
template <int B>
   
using int_t = typename _int_t_helper<B>::type;
}

char (&Function(...))[99];

template <int S>
meow
::int_t<S * CHAR_BIT> Function(unsigned char (&)[S]);

int main()
{
   
unsigned char buffer1[1];
   
unsigned char buffer2[2];
   
unsigned char buffer3[3];
   
unsigned char buffer4[4];
    std
::printf("%zu %zu %zu %zu\n", sizeof(Function(buffer1)), sizeof(Function(buffer2)),
               
sizeof(Function(buffer3)), sizeof(Function(buffer4)));
}

Melissa

Tony V E

unread,
Sep 6, 2016, 4:46:09 PM9/6/16
to Standard Proposals
Sure, as in LWG2543.  Just need to be able to "ask" via sfinae whether int_t<12> is a usable type or not.  Without it going straight to "ill-formed do not pass sfinae, do not collect 200 dollars".

P.S. the resolution of LWG2543:

-?- For any type T that is not of integral or enumeration type, or for which neither the library nor the user provides an explicit or partial specialization of the class template hash, the specialization of hash<T> has the following properties:

  • is_default_constructible_v<hash<T>> is false
  • is_copy_constructible_v<hash<T>> is false
  • is_move_constructible_v<hash<T>> is false
  • is_copy_assignable_v<hash<T>> is false
  • is_move_assignable_v<hash<T>> is false
  • hash<T> is not a function object type (20.14 [function.objects])

[Note: this means that the specialization of hash exists, but any attempts to use it as a Hash will be ill-formed. — end note]


basically - including the note - says  "if no one (including the library) specialized hash<T>, then the library specialized hash<T> (with a strange specialization)".

ie it says that the library didn't specialize it, then it did.  Or where does the specialization - that does exist according to the note - come from, if not the library?

I understand what it is trying to say, but the wording (or just the note) might still be a bit off?


--
Be seeing you,
Tony

Ville Voutilainen

unread,
Sep 6, 2016, 4:51:52 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 23:42, Myriachan <myri...@gmail.com> wrote:
> On Tuesday, September 6, 2016 at 1:24:43 PM UTC-7, Ville Voutilainen wrote:
>>
>> >> I am unaware of a way to sfinae on mentioning a specialization. I know
>> >> how
>> >> to sfinae on expressions that use the type. As in
>> >> http://cplusplus.github.io/LWG/lwg-active.html#2543
>>
>
> I mean substitution failure for SFINAE along these lines, where the output
> is "1 2 99 4":


Well, I can give you what you want either with concepts or with a
suitably-enable_if-constrained alias template.
The wording "using the specialization is ill-formed" gives you SFINAE,
since I didn't add ", no diagnostic required".

Ville Voutilainen

unread,
Sep 6, 2016, 4:58:22 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 23:46, Tony V E <tvan...@gmail.com> wrote:
> P.S. the resolution of LWG2543:
>
> -?- For any type T that is not of integral or enumeration type, or for which
> neither the library nor the user provides an explicit or partial
> specialization of the class template hash, the specialization of hash<T> has
> the following properties:
>
> is_default_constructible_v<hash<T>> is false
> is_copy_constructible_v<hash<T>> is false
> is_move_constructible_v<hash<T>> is false
> is_copy_assignable_v<hash<T>> is false
> is_move_assignable_v<hash<T>> is false
> hash<T> is not a function object type (20.14 [function.objects])
>
> [Note: this means that the specialization of hash exists, but any attempts
> to use it as a Hash will be ill-formed. — end note]
>
>
> basically - including the note - says "if no one (including the library)
> specialized hash<T>, then the library specialized hash<T> (with a strange
> specialization)".
>
> ie it says that the library didn't specialize it, then it did. Or where

No, the library didn't specialize it, it achieved the effect of that wording
with the primary template. The library didn't provide an explicit or
partial specialization
for the type T. The specialization hash<T> for non-integral non-enum
type is a specialization of the primary
template. (Yeah, that P/R has been implemented. I know, I'm annoying
that way, I often
implement the P/Rs I write before sending them to lwgchair).

I suppose the note could say "is a complete type" instead of "exists".

Ville Voutilainen

unread,
Sep 6, 2016, 5:07:01 PM9/6/16
to ISO C++ Standard - Future Proposals
On 6 September 2016 at 23:58, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> No, the library didn't specialize it, it achieved the effect of that wording
> with the primary template. The library didn't provide an explicit or
> partial specialization
> for the type T. The specialization hash<T> for non-integral non-enum
> type is a specialization of the primary
> template. (Yeah, that P/R has been implemented. I know, I'm annoying
> that way, I often
> implement the P/Rs I write before sending them to lwgchair).
>
> I suppose the note could say "is a complete type" instead of "exists".

And, to answer your question "where did that specialization come from,
if not the library?", I suggest
you look at [temp.inst], which explains how the language conjures that
specialization out of thin air^W^W^W^Wfrom
the primary template when the program you wrote uses the specialization.

Myriachan

unread,
Sep 6, 2016, 5:25:44 PM9/6/16
to ISO C++ Standard - Future Proposals

Does this work?

(int_t, uint_t)
int_t<B> is an alias for intB_t if the implementation provides the type intB_t; otherwise, using the specialization int_t<B> is ill-formed.

(int_least_t, uint_least_t, int_fast_t, uint_fast_t)
int_least_t<B> is an alias for int_leastN_t, where N is the smallest integer greater than or equal to B such that the implementation provides int_leastN_t.  If B is less than 1, or if B is greater than the largest such integer N, using the specialization int_least_t<B> is ill-formed.

Would Standardese repeat those lines for all four variants, or somehow reword it to apply to all four?

Does this need a "Note:" to make explicit the intent that the ill-formed cases are meant to cause substitution failure for SFINAE, rather than "hard" errors?

Melissa

Arthur O'Dwyer

unread,
Sep 6, 2016, 7:16:45 PM9/6/16
to ISO C++ Standard - Future Proposals
On Tuesday, September 6, 2016 at 2:25:44 PM UTC-7, Myriachan wrote:
On Tuesday, September 6, 2016 at 1:51:52 PM UTC-7, Ville Voutilainen wrote:
On 6 September 2016 at 23:42, Myriachan <myri...@gmail.com> wrote:
> I mean substitution failure for SFINAE along these lines, where the output
> is "1 2 99 4":

Well, I can give you what you want either with concepts or with a
suitably-enable_if-constrained alias template.
The wording "using the specialization is ill-formed" gives you SFINAE,
since I didn't add ", no diagnostic required".

Does this work?

(int_t, uint_t)
int_t<B> is an alias for intB_t if the implementation provides the type intB_t; otherwise, using the specialization int_t<B> is ill-formed.

I'm not sure it's meaningful to talk about "using such-and-such a specialization" (types can't be odr-used, right?).
I also think you're waaay overthinking this. The correct legalese will be drafted for you by LWG if it gets that far. Your goal should be to communicate your intended semantics as clearly as possible.  For example, I would suggest merely:

The type int_t<B> is a synonym for intB_t if the implementation provides the type intB_t; otherwise, the type does not exist.
int_least_t<B> is a synonym for int_leastN_t, where N is the smallest integer greater than or equal to B such that the implementation provides int_leastN_t; otherwise, the type does not exist.

I copied the wording "is a synonym for" from the definition of std::nullptr_t in 18.2.2 [support.types.nullptr] /1.

I would leave out all mention of "ill-formed" and as much as possible about the range of B; for example, I see no reason intleast_t<0> shouldn't be int8_t.

You can implement a type's "not existing" (in a SFINAE-friendly way) via

    template<int i> struct _int;
    template<> struct _int<8> { using type = int8_t; };
    template<> struct _int<16> { using type = int16_t; };
    template<> struct _int<32> { using type = int32_t; };
    template<int i> using int_t = typename _int<i>::type;

int_t<7> expands to _int<7>::type, which requires the implicit instantiation of _int<7>, which yields an incomplete class type; and then looking up the 'type' member of that incomplete class type fails. Which is certainly SFINAE-friendly (SFINAE itself being explained obliquely in N4606 section 14.8.2 [temp.deduct] /8, if I understand correctly).


Does this need a "Note:" to make explicit the intent that the ill-formed cases are meant to cause substitution failure for SFINAE, rather than "hard" errors?

Historically, no, the Standard tends not to mention when SFINAE is the reason for things.

HTH,
–Arthur

Ville Voutilainen

unread,
Sep 6, 2016, 7:29:43 PM9/6/16
to ISO C++ Standard - Future Proposals
On 7 September 2016 at 02:16, Arthur O'Dwyer <arthur....@gmail.com> wrote:
> I'm not sure it's meaningful to talk about "using such-and-such a
> specialization" (types can't be odr-used, right?).

I wasn't talking about odr-use. We could of course steal wording from
the spec of deleted function definitions,
which says
"A program that refers to a deleted function implicitly or explicitly,
other than to declare it, is ill-formed."
The "use" example is about main, which says
"The function main shall not be used within a program."
It's certainly meaningful to talk about using the specialization, and
it's not all that hard to interpret it
as meaning mentioning the type, because that's what it means for main;
you can't decltype it or do anything
with it, it can't be used, and that's not limited to the narrow world
of odr-use.

> You can implement a type's "not existing" (in a SFINAE-friendly way) via
> template<int i> struct _int;
> template<> struct _int<8> { using type = int8_t; };
> template<> struct _int<16> { using type = int16_t; };
> template<> struct _int<32> { using type = int32_t; };
> template<int i> using int_t = typename _int<i>::type;
> int_t<7> expands to _int<7>::type, which requires the implicit instantiation
> of _int<7>, which yields an incomplete class type; and then looking up the
> 'type' member of that incomplete class type fails. Which is certainly
> SFINAE-friendly (SFINAE itself being explained obliquely in N4606 section
> 14.8.2 [temp.deduct] /8, if I understand correctly).

Well, that part of the idea works, but an implementation of this idea
needs to disable
_int<8> if int8_t isn't provided, so an explicit specialization won't cut it.

>> Does this need a "Note:" to make explicit the intent that the ill-formed
>> cases are meant to cause substitution failure for SFINAE, rather than "hard"
>> errors?
> Historically, no, the Standard tends not to mention when SFINAE is the
> reason for things.

You might want to entertain the idea of adding a note that says that
the unwanted type is
ill-formed in the immediate context. Vague wording on that part will
open the possibility that
implementations will mistakenly static_assert inside a class template
definition, which does not do what
you want.

Tony V E

unread,
Sep 6, 2016, 7:44:53 PM9/6/16
to ISO C++ Standard - Future Proposals
And to be clear about your intent, just use the words 'sfinae friendly' in the non-wording section, and LWG will know what to do. 

Sent from my BlackBerry portable Babbage Device
From: Arthur O'Dwyer
Sent: Tuesday, September 6, 2016 7:16 PM
To: ISO C++ Standard - Future Proposals
Subject: Re: [std-proposals] What header should int_t go to?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Richard Smith

unread,
Sep 6, 2016, 9:45:44 PM9/6/16
to std-pr...@isocpp.org
On Tue, Sep 6, 2016 at 2:25 PM, Myriachan <myri...@gmail.com> wrote:
On Tuesday, September 6, 2016 at 1:51:52 PM UTC-7, Ville Voutilainen wrote:
On 6 September 2016 at 23:42, Myriachan <myri...@gmail.com> wrote:
> I mean substitution failure for SFINAE along these lines, where the output
> is "1 2 99 4":


Well, I can give you what you want either with concepts or with a
suitably-enable_if-constrained alias template.
The wording "using the specialization is ill-formed" gives you SFINAE,
since I didn't add ", no diagnostic required".

Does this work?

(int_t, uint_t)
int_t<B> is an alias for intB_t if the implementation provides the type intB_t; otherwise, using the specialization int_t<B> is ill-formed.

I think this is overly restrictive; if an implementation can provide int_t<N> for other values of N, I don't see why that should be disallowed.

(int_least_t, uint_least_t, int_fast_t, uint_fast_t)
int_least_t<B> is an alias for int_leastN_t, where N is the smallest integer greater than or equal to B such that the implementation provides int_leastN_t.  If B is less than 1, or if B is greater than the largest such integer N, using the specialization int_least_t<B> is ill-formed.

Would Standardese repeat those lines for all four variants, or somehow reword it to apply to all four?

Does this need a "Note:" to make explicit the intent that the ill-formed cases are meant to cause substitution failure for SFINAE, rather than "hard" errors?

Melissa

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Patrice Roy

unread,
Sep 6, 2016, 9:56:57 PM9/6/16
to std-pr...@isocpp.org
As far as the original question went, my spontaneous answer was «well, let's have a <stdint> (probably bikeshed) counterpart to <cstdint>, just like we have a <limits> counterpart to <climits> where we provide templated services akin to the C macros».

I started writing this and stopped. Would it be too small a header? Could it be a nice destination for an eventual bigint (name to be defined; there are proposals but I'm not totally up to date here) type? It seemed natural to me, but I'm not sure I've thought this through.

So there: it's out in the open, and let's kill it if it doesn't make sense :)

Tony V E

unread,
Sep 6, 2016, 11:31:13 PM9/6/16
to Patrice Roy
I have no problems with small headers. YMMV. 

I think BigInt will be expensive relative to int_t<>, so I'd prefer it to be in a separate header.

Although maybe when modules show up gaging 'expensive' and headers etc might all change?


Sent from my BlackBerry portable Babbage Device
From: Patrice Roy
Sent: Tuesday, September 6, 2016 9:56 PM
Subject: Re: [std-proposals] What header should int_t go to?
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Myriachan

unread,
Sep 7, 2016, 4:41:37 PM9/7/16
to ISO C++ Standard - Future Proposals
On Tuesday, September 6, 2016 at 6:45:44 PM UTC-7, Richard Smith wrote:

I think this is overly restrictive; if an implementation can provide int_t<N> for other values of N, I don't see why that should be disallowed.


Yeah, you're right.  I would say that whatever types exist in cstdint ought to exist in the templates, though.  (C++ doesn't state that an implementation can have these types in <cstdint> for numbers except 8, 16, 32 and 64, but C does state this.  I think that this should be corrected, with an implementation being allowed to define a std::int28_t.)

I did come up with another issue, though.  This rule is in [temp.res]/8:

"If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required."

int_t<B> as I wanted to define it would potentially violate this rule.  If an implementation has no types that meet the requirements of int_t<B> for any B, then an implementation would need an int_t somewhat like this:

    template <int B> struct _undefined_struct;
    template <int B> using int_t = typename _undefined_struct<B>::_type;

But then no valid template instantiation would exist, violating the rule, even though it's actually a desirable outcome here (SFINAE could detect that int_t<B> doesn't exist for some B).

Melissa

Richard Smith

unread,
Sep 7, 2016, 5:57:00 PM9/7/16
to std-pr...@isocpp.org
On Wed, Sep 7, 2016 at 1:41 PM, Myriachan <myri...@gmail.com> wrote:
On Tuesday, September 6, 2016 at 6:45:44 PM UTC-7, Richard Smith wrote:

I think this is overly restrictive; if an implementation can provide int_t<N> for other values of N, I don't see why that should be disallowed.


Yeah, you're right.  I would say that whatever types exist in cstdint ought to exist in the templates, though.  (C++ doesn't state that an implementation can have these types in <cstdint> for numbers except 8, 16, 32 and 64, but C does state this.  I think that this should be corrected, with an implementation being allowed to define a std::int28_t.)

Yes, Thomas and I noticed that when working on p0175r1. It seemed odd to us too, and probably a defect. It was also not completely clear whether the _MIN/_MAX macros were supposed to be optional in C++. I don't know of a reason for C++ to diverge from C here.

I think we can go further than <cstdint> does: we could require that int_t<B> works at least for every B where the implementation provides at least one (standard or extended) signed integer type that is 2's complement and B bits wide. (I'm somewhat on the fence on C's "no padding bits" requirement, but perhaps we should include that too for consistency.) <cstdint> only requires this for the cases where B is 8, 16, 32, or 64, and in other cases the implementation is permitted but not required to provide the type.

I did come up with another issue, though.  This rule is in [temp.res]/8:

"If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required."

int_t<B> as I wanted to define it would potentially violate this rule.  If an implementation has no types that meet the requirements of int_t<B> for any B, then an implementation would need an int_t somewhat like this:

    template <int B> struct _undefined_struct;
    template <int B> using int_t = typename _undefined_struct<B>::_type;

But then no valid template instantiation would exist, violating the rule, even though it's actually a desirable outcome here (SFINAE could detect that int_t<B> doesn't exist for some B).

Someone should write a paper proposing that we drop support for non-2s'-complement integer representations...

Arthur O'Dwyer

unread,
Sep 8, 2016, 5:37:37 PM9/8/16
to ISO C++ Standard - Future Proposals
On Wed, Sep 7, 2016 at 1:41 PM, Myriachan <myri...@gmail.com> wrote:
On Tuesday, September 6, 2016 at 6:45:44 PM UTC-7, Richard Smith wrote:

I think this is overly restrictive; if an implementation can provide int_t<N> for other values of N, I don't see why that should be disallowed.

Yeah, you're right.  I would say that whatever types exist in cstdint ought to exist in the templates, though.  (C++ doesn't state that an implementation can have these types in <cstdint> for numbers except 8, 16, 32 and 64, but C does state this.  I think that this should be corrected, with an implementation being allowed to define a std::int28_t.)

Right. I think drawing an equivalence between intN_t and int_t<N> is unobjectionable.
Any implementation that provides either int128_t or int_t<128> is already dealing in vendor-specific extensions; it's totally fine for the standard to require that any such extensions be internally consistent.


I did come up with another issue, though.  This rule is in [temp.res]/8:

"If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required."

int_t<B> as I wanted to define it would potentially violate this rule.  If an implementation has no types that meet the requirements of int_t<B> for any B, then an implementation would need an int_t somewhat like this:

    template <int B> struct _undefined_struct;
    template <int B> using int_t = typename _undefined_struct<B>::_type;

The trick is, "somewhat" like this. Perhaps you're right that it couldn't be *exactly* this; but in that case, it would be up to the implementation to provide an int_t that worked.  For example, on such a hypothetical compiler, I'm pretty sure that this would work:

    template <int B> struct _undefined_struct;
    template<> struct _undefined_struct<-1>;
    template <int B> using int_t = typename _undefined_struct<B>::_type;

Anyway, [temp.res]/8 has a bad habit of coming up as a stumbling block for writing code that works on Sufficiently Smart Compilers (none of which exist today); it probably needs some committee attention, but it shouldn't get in the way of standardizing some random integer types. :P

HTH,
–Arthur

John McFarlane

unread,
Sep 22, 2016, 12:28:48 PM9/22/16
to ISO C++ Standard - Future Proposals
Arthur just brought this proposal to my attention. I have submitted a similar proposal:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0381r0.html

In it, the equivalent to std::int_t<BITS> would be set_width_t<int, BITS>. This type could be user-specialized for non-built-in integral types.

Note that that name is certainly going to change (perhaps make_int_t or make_bitwidth_t) and that I suggest fast and least variants.

D. B.

unread,
Sep 22, 2016, 2:43:45 PM9/22/16
to std-pr...@isocpp.org
On Thu, Sep 22, 2016 at 5:28 PM, John McFarlane <mcfarla...@gmail.com> wrote:

In it, the equivalent to std::int_t<BITS> would be set_width_t<int, BITS>. This type could be user-specialized for non-built-in integral types.

Note that that name is certainly going to change (perhaps make_int_t or make_bitwidth_t) and that I suggest fast and least variants.

--


make_ isn't any better though, is it? as a prefix for types, that too seems both redunant (vs the _t suffix) and a recipe for confusion (wrt make_*() functions)

 

John McFarlane

unread,
Sep 22, 2016, 10:23:57 PM9/22/16
to std-pr...@isocpp.org
The appeal of `make_` is that there is already `make_signed` which is closely related: it takes one type and changes a single attribute about it, yielding another type.

The `_t` variants are a convenience types; they're another matter altogether. For example, `make_signed_t<T>` which is shorthand for `typename make_signed<T>::type`.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

D. B.

unread,
Sep 23, 2016, 3:20:52 AM9/23/16
to std-pr...@isocpp.org
On Fri, Sep 23, 2016 at 3:23 AM, John McFarlane <jo...@mcfarlane.name> wrote:
The appeal of `make_` is that there is already `make_signed` which is closely related: it takes one type and changes a single attribute about it, yielding another type.

The `_t` variants are a convenience types; they're another matter altogether. For example, `make_signed_t<T>` which is shorthand for `typename make_signed<T>::type`.


make_signed, of course! I forgot about that one (despite having just used it a few weeks ago). In retrospect I would have to apply the same scepticism to it too, although it didn't cross my mind at the time. :D But that aside, you have a fair basis for choosing the name.

As an aside, I wonder, will the stdlib ever start putting its type helper structs in detail namespaces (as they are effectively just boilerplate) and only expose the related using alias - as I do with some of my template stuff - or is there a reason to keep both available as part of the interface?

John McFarlane

unread,
Sep 23, 2016, 4:48:01 PM9/23/16
to ISO C++ Standard - Future Proposals
On Friday, September 23, 2016 at 12:20:52 AM UTC-7, D. B. wrote:

As an aside, I wonder, will the stdlib ever start putting its type helper structs in detail namespaces (as they are effectively just boilerplate) and only expose the related using alias - as I do with some of my template stuff - or is there a reason to keep both available as part of the interface?

If there were any reason (perhaps a map of type transforms which required all elements to have a `::type` member), one could write their own `::type` variant from the `_t` definition.
Reply all
Reply to author
Forward
0 new messages