Skip to main content
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case for std::size_t: http://stackoverflow.com/questions/32915434https://stackoverflow.com/questions/32915434

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case for std::size_t: http://stackoverflow.com/questions/32915434

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case for std::size_t: https://stackoverflow.com/questions/32915434

Spelling and grammar; character code is not necessarily ASCII
Source Link
  1. Some types, like cstdint aliases or, at least purely theoretically, even std::size_t, may be (but don’t have to) be bond) bound to char, signed char or unsigned char. In practisepractice, std::int_least8_t seems to be often bondbound to signed char and std::uint_least8_t – to unsigned char. This seems odd, since semantically, all those types are supposed to represent integers rather than characters.
  2. In case of variables of a character type, the >> operator writes the ASCIIcharacter code of the first non-whitespace character of the input stream into the variable, while the << operator outputs a character of the ASCIIcharacter code equal to the value of the variable.
  3. Therefore it may happen that if we, for example, declare a variable as int_least8_t and use the input operator or the output operator on it, then the results will be far from expected. This seems to be even more awkward since whether such aliases are bondbound to character types or not depends only on the implementation and is a priori unknown.

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case offor std::size_t: http://stackoverflow.com/questions/32915434/is-it-guaranteed-that-size-t-vectorsize-type-etc-typedefs-wont-bind-to-a-chhttp://stackoverflow.com/questions/32915434

  1. Some types, like cstdint aliases or, at least purely theoretically, even std::size_t, may (but don’t have to) be bond to char, signed char or unsigned char. In practise std::int_least8_t seems to be often bond to signed char and std::uint_least8_t – to unsigned char. This seems odd, since semantically, all those types are supposed to represent integers rather than characters.
  2. In case of variables of a character type, the >> operator writes the ASCII code of the first non-whitespace character of the input stream into the variable, while the << operator outputs a character of the ASCII code equal to the value of the variable.
  3. Therefore it may happen that if we, for example, declare a variable as int_least8_t and use the input operator or the output operator on it, then the results will be far from expected. This seems to be even more awkward since whether such aliases are bond to character types or not depends only on the implementation and is a priori unknown.

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case of std::size_t: http://stackoverflow.com/questions/32915434/is-it-guaranteed-that-size-t-vectorsize-type-etc-typedefs-wont-bind-to-a-ch

  1. Some types, like cstdint aliases or, at least purely theoretically, even std::size_t, may be (but don’t have to be) bound to char, signed char or unsigned char. In practice, std::int_least8_t seems to be often bound to signed char and std::uint_least8_t – to unsigned char. This seems odd, since semantically, all those types are supposed to represent integers rather than characters.
  2. In case of variables of a character type, the >> operator writes the character code of the first non-whitespace character of the input stream into the variable, while the << operator outputs a character of the character code equal to the value of the variable.
  3. Therefore it may happen that if we, for example, declare a variable as int_least8_t and use the input operator or the output operator on it, then the results will be far from expected. This seems to be even more awkward since whether such aliases are bound to character types or not depends only on the implementation and is a priori unknown.

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case for std::size_t: http://stackoverflow.com/questions/32915434

Source Link
gaazkam
  • 581
  • 2
  • 14

Enforcing correct input/output of integers

The problem:

  1. Some types, like cstdint aliases or, at least purely theoretically, even std::size_t, may (but don’t have to) be bond to char, signed char or unsigned char. In practise std::int_least8_t seems to be often bond to signed char and std::uint_least8_t – to unsigned char. This seems odd, since semantically, all those types are supposed to represent integers rather than characters.
  2. In case of variables of a character type, the >> operator writes the ASCII code of the first non-whitespace character of the input stream into the variable, while the << operator outputs a character of the ASCII code equal to the value of the variable.
  3. Therefore it may happen that if we, for example, declare a variable as int_least8_t and use the input operator or the output operator on it, then the results will be far from expected. This seems to be even more awkward since whether such aliases are bond to character types or not depends only on the implementation and is a priori unknown.

An example of the above problems: http://ideone.com/JgyFhR A proof that purely theoretically, this can even be the case of std::size_t: http://stackoverflow.com/questions/32915434/is-it-guaranteed-that-size-t-vectorsize-type-etc-typedefs-wont-bind-to-a-ch

I’ve attempted to write a generic solution to all those problems:

#ifndef INTIO_H
#define INTIO_H
 
#include <istream>
#include <ostream>
#include <type_traits>
#include <limits>
 
template
<class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
class integer_IO
{
  T &val;
 
public:
 
  integer_IO(T &arg) : val(arg) {}
  integer_IO(T &&arg) : val(arg) {}
 
  friend std::istream &operator>> (std::istream &is, integer_IO<T> &&i)
  {
    using TT = decltype(+i.val);
    TT hlp;
    is >> hlp;
    TT constexpr minval = static_cast<TT>(std::numeric_limits<T>::min());
    TT constexpr maxval = static_cast<TT>(std::numeric_limits<T>::max());
    i.val = static_cast<T>(hlp > maxval ? maxval : hlp < minval ? minval : hlp);
    if(hlp > maxval || hlp < minval)
      is.setstate(std::ios::failbit);
    return is;
  }
 
  friend std::ostream &operator<< (std::ostream &os, integer_IO<T> const &&i)
  {
    os << +i.val;
    return os;
  }
};
 
template
<class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
integer_IO<T> intIO(T &arg)
{
  return integer_IO<T>(arg);
}
 
template
<class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
integer_IO<T> intIO(T &&arg)
{
  return integer_IO<T>(arg);
}
 
#endif

The usage of this wrapper is simple:

#include <iostream>
#include <cstdint>
#include "intIO.hpp"
using namespace std;
 
int twoplustwo()
{
  return 2+2;
}
 
int main()
{
  int_least8_t i;
  cin >> intIO(i);
  cout << intIO(i) << '\n';
  cout << intIO(twoplustwo()) << '\n';
}

What is your opinion of my code?