According to answers to this questions Is overloading on all of the fundamental integer types is sufficient to capture all integers? overloading of all fundamental types may not be able to handle types like int8_t
int64_t
etc. On another side according to documentation std::ostream formatted output and std::istream formatted input is implemented exactly by overloading all fundamental types. So on platform where int8_t
and others could not be handled by such overloading how C++ streams would have to handle them? Would it fail to compile? Would standard library implementors have to provide additional undocumented methods? Something else?
-
I don't get your question. If `int8_t` is not available on a platform, `std::ostream` and family can't possibly overload them. On that platform, `int8_t` doesn't exist and isn't a type as a result. – Rakete1111 Jan 09 '17 at 18:17
-
`int8_t` can always be promoted to a fundamental type, if necessary. The potentially problematic one is `int64_t`, if your platform has 32-bit `long long`. – Useless Jan 09 '17 at 18:17
-
1@Rakete1111 read question in link, problem is not that `int8_` is not defined, but that it is not an alias to a fundamental type. – Slava Jan 09 '17 at 18:22
-
@Useless I doubt promotion will work well with overloading. But even if it does, it would not help with references for `std::istream` – Slava Jan 09 '17 at 18:23
-
Integral promotion definitely does work with overloading (it's an available implicit conversion), although you're right about `istream`. – Useless Jan 09 '17 at 18:27
-
On systems where `char` is wider than 8 bits, you cannot have an `int8_t`. For example, `sizeof(char)`is always 1, so what would `sizeof(int8_t)` be? 0.5? – Bo Persson Jan 09 '17 at 18:49
-
@BoPersson question is not about what `intXX_t` types I would have. Question is if I do have them but they cannot be handled by overloading for fundamental types, what standard lib would do. – Slava Jan 09 '17 at 19:02
-
@BoPersson read answers to question I provided link to. There is a claim that compiler is allowed to create integer types that would be different than fundamental and it is possible such types would be there. – Slava Jan 09 '17 at 19:06
-
1@Useless You can't get 32-bit `long long`. That one's required to be 64 bits minimum. – T.C. Jan 09 '17 at 19:21
-
@NicolBolas That the absolute value of `LLONG_MIN` and `LLONG_MAX` are required to be at least 9223372036854775807 each (WG14 N1570, §5.2.4.2.1, which is incorporated by [\[basic.fundamental\]/3](https://timsong-cpp.github.io/cppwp/basic.fundamental#3))? – T.C. Jan 09 '17 at 20:28
2 Answers
For integer types, [istream] defines:
basic_istream<charT,traits>& operator>>(bool& n);
basic_istream<charT,traits>& operator>>(short& n);
basic_istream<charT,traits>& operator>>(unsigned short& n);
basic_istream<charT,traits>& operator>>(int& n);
basic_istream<charT,traits>& operator>>(unsigned int& n);
basic_istream<charT,traits>& operator>>(long& n);
basic_istream<charT,traits>& operator>>(unsigned long& n);
basic_istream<charT,traits>& operator>>(long long& n);
basic_istream<charT,traits>& operator>>(unsigned long long& n);
Any code of the form is >> x
may fail to compile if x
is an integer type that's not in that list.
As a quality of implementation issue, an implementation which offers extended integer types could add operator>>
overloads for those types. This is permitted by [member.functions]/2 (as noted by hvd in comments), talking about classes in the standard library:
An implementation may declare additional non-virtual member function signatures within a class:
[...]
- by adding a member function signature for a member function name.
A call to a member function signature described in the C ++ standard library behaves as if the implementation declares no additional member function signatures.
This is a stronger guarantee than the general rule that implementations may add extensions that don't break conforming programs. The behaviour of conforming programs using SFINAE might be affected by the presence of the extra overloads.
For output, integer types not in the list will be implicitly convertible to another integer type which is in the list.
-
"could add operator>> overloads for those types." would that not be violation of standard? – Slava Jan 09 '17 at 21:00
-
@Slava: No. Implementations are permitted to add whatever other functions to the standard that they want as standard library extensions. So long as they do not change the observable behavior of a conforming program, outside of the boundaries of the specification. – Nicol Bolas Jan 09 '17 at 21:01
-
@Slava The standard allows implementations to add overloads of member functions, so long as they do not interfere with calls that are specified to be valid. See [global.functions] and [member.functions], and specifically the footnote attached to the latter. – Jan 09 '17 at 21:08
-
@M.M This is a stronger exception than simply not breaking conforming code. Without this exception, conforming code *could* use SFINAE to detect that a certain call would be invalid. Because of this exception, the call is allowed to be valid anyway. – Jan 09 '17 at 21:08
So on platform where
int8_t
and others could not be handled by such overloading how C++ streams would have to handle them?
As far as integer insertion is concerned (operator<<), it would handle them in accord with standard C++ overload resolution. Extended integer types are still integer types and follow the rules of implicit conversion for the purpose of overload resolution.
For example, int8_t
can be upconverted to any signed integer type large enough to hold it. So if int8_t
is an extended integer type rather than an alias of the standard integer types, it can be upconverted to one of the standard ones, in accord with overload resolution rules.
For integer extraction (operator>>
), this requires a non-const
reference to a live integer, so conversion is not possible. Therefore, if you do not provide one of the explicit types that operator>>
is overloaded for, your code should fail to compile.
The best you might get is if an implementation adds overloads specifically for those types, but you can't rely on that.
It should be noted that C++17's new to_chars
and from_chars
are explicitly stated by the standard to have overloads for all signed&unsigned integer types (and char
). So that includes extended integer types.
Would it fail to compile?
For insertion, that depends on the types used. int8_t
is safe because there are standard integer types that are larger than it. It may have different behavior than you expect, but it will work.
By contrast, there is no guarantee that int_least64_t
or intmax_t
is not larger than long long
. And implicit conversion can't go from larger to smaller. In those cases, you get a compile error.
For extraction, you get compilation failures if you don't match the types.
Would standard library implementors have to provide additional undocumented methods?
No. They are permitted to do so, but that's not something you can rely on.
int8_t
is a special case because of the treatment of how it can be implemented.
char
serves double duty as a byte-sized type and a character type. Because it's a character type, iostream operations will treat uses of char
differently from how it treats integer types. With integers, it will parse/generate integer strings. With a character, it assumes you mean to read a character.
A valid implementation of int8_t
could be as an alias of signed char
or just char
if it is signed. As such, use of it with stream operations will treat it as a character.
A valid implementation of int8_t
could be as an extended integer type, a type which is distinct from char
. As such, the value will be upconverted to a larger integer type that matches one of the standard ones, in accord with overload resolution rules. And therefore, it will call one of these.

- 449,505
- 63
- 781
- 982
-
"For example, int8_t can be upconverted to any signed integer type large enough to hold it." This is not the case for `std::istream` – Slava Jan 09 '17 at 20:40
-
@Slava: Of course it isn't. That's because your implementation implements `int8_t` as `signed char` or something of that sort. Which is perfectly legal and will call that the `char` overload for stream operations. That is not a *required implementation*; it is merely one possibility. If `int8_t` were implemented as an extended integer type, then it would not trigger that overload; it would trigger a different overload. That's also a valid implementation. – Nicol Bolas Jan 09 '17 at 20:42
-
@Slava: To put it another way, the standard requires that you can apply `operator<<` to an `int8_t`. *Exactly* what will happen, exactly which overload will be called, is not specified. – Nicol Bolas Jan 09 '17 at 20:43
-
"Exactly what will happen when you do so however is not specified" if I understand correctly exact list of member overloads is listed explicitly, so that actually is the question, how it would be implemented not to violate standard. – Slava Jan 09 '17 at 20:45
-
@Slava: ***Either way is valid!*** What exactly is it that you don't understand about that? It's legal to make `int8_t` an alias of `char`. It's *also legal* to make it an extended integer type. These two possible implementations have two distinctly different behaviors when calling `operator<<` on streams. Therefore, you *cannot* rely on any particular behavior if you want your code to be cross platform. – Nicol Bolas Jan 09 '17 at 20:47
-
I do not understand how can any `operator>>` from the list could be used when `int8_t` or `int64_t` or whatever is extended type. – Slava Jan 09 '17 at 20:49
-
@Slava perhaps you should rewrite your question to focus on that issue, with a code sample – M.M Jan 09 '17 at 20:50
-
@Slava: Look, at this point, I don't know how I can possibly explain it more clearly. What exactly will happen if you apply `int8_t` is *implementation-defined*. Like I just said. You cannot rely on a specific behavior. – Nicol Bolas Jan 09 '17 at 20:50
-
I am not asking for specific behavior. I am saying that from my understanding `operator>>` cannot be resolved when `intXX_t` type is extended and you only provide methods defined in standard. – Slava Jan 09 '17 at 20:53
-
@Slava: I answered that in my very first paragraph. Again, I don't know how to say it any more clearly. Integer types can be converted to larger ones. And extended integer types *are still integer types*. – Nicol Bolas Jan 09 '17 at 20:57
-
"Integer types can be converted to larger ones." Again that will not happen for `std::istream` – Slava Jan 09 '17 at 20:58
-
@Slava: Please read this part: ***if `int8_t` is an extended integer type rather than an alias of the standard integer types***. If your `int8_t` is *not* an extended integer type, if it is a standard integer type, then no upconversion will be necessary. – Nicol Bolas Jan 09 '17 at 21:00
-
But if that does apply upconversion cannot be used for `std::istream`. Should we start again? – Slava Jan 09 '17 at 21:03
-
@Slava: ...I don't understand what you're saying. If `int8_t` is an extended integer type, then it will not call one of the `char` overloads. If your implementation *does* call one of the `char` overloads, then your `int8_t` is *not an extended integer type*. Why do you believe extended integer types cannot be upconverted? Do you not understand that your implementation of `int8_t` is *not* an extended integer type? – Nicol Bolas Jan 09 '17 at 21:04
-
You say in case when `intXX_t` type is extended it would work because of upconversion. I say this is not the answer to my question as upconversion would not happen with `std::istream`. So you only answer for `std::ostream` but that only half of my question. – Slava Jan 09 '17 at 21:07
-
@Slava: OK, I see your point. I added additions to my answer to cover those cases. – Nicol Bolas Jan 09 '17 at 21:14