2

Background:

I have template stream operators (e.g. operator << (ostream &, std::vector <T>)) (that output container elements that may possibly be of some 8-bit integer type, (e.g. unsigned char, int_least8_t, et cetera).

Problem:

Default is that these types are output as char (ASCII). I only used char (or wchar_t or whatever) for ASCII variables, never unsigned/signed types. How do I get these other 8-bit types to always be output as signed int / unsigned int (numbers) instead, even when the caller doesn't know the type?

First tries:

I have tried (with GCC) for example defining operator << (ostream &, unsigned char) with a cast in it (i.e. stream << static_cast <int> (value). That works for unsigned char values, but then uint8_t still gets output as a char.

The same underlying type (i.e. unsigned/signed char can not be used in overloads, so I can't define an overload of for example operator << (ostream &, int_fast8_t).

StellarVortex
  • 577
  • 4
  • 19

5 Answers5

3

You're confusing the actual data held in a variable, with whatever representation you choose for printing it.

Think of it this way: chars, ints, doubles, longs, whatevers, they're all just chunks of memory for you to store numbers in. A char is a number between 0 and 255 (or -128 and 127) -- you can choose to represent it as an ASCII character, or as a number, or as stars in the sky with the aid of OpenGL.

If you want to see the number behind the character 'a', just instruct your program to treat that chunk of memory (that for you contains an 'a') as a number. Use casts. Here:

http://www.cplusplus.com/doc/tutorial/typecasting/

See if that helps!

slezica
  • 63,258
  • 20
  • 91
  • 152
  • `+1` for addressing the underlying confusion of the OP, rather than showing which syntax to use. – sbi Oct 29 '10 at 08:17
  • This is not possible from within a template operator, since it would require me to know the type beforehand. – StellarVortex Nov 01 '10 at 07:24
2

One way that comes to mind is using type traits to define the output type for each type. You would have to declare that for every type by hand. The traits could be defined as a template struct that is specialized for every data-type that has a different output-type than the data-type itself:

template< T >
struct output_trait {
    typedef const T & output_type;
}

In your operator you write:

std::cout << static_cast< output_trait< T >::output_type >( variable ) << std::endl;

This will do no cast by default, but for types for which output_trait is specialized it will do a cast:

template<>
struct output_trait< unsigned char > {
    typedef unsigned int output_type;
}
Björn Pollex
  • 70,106
  • 28
  • 177
  • 265
  • Thanks, I would never have guessed that myself. (The other answers completely missed the part about the template container.) – StellarVortex Oct 31 '10 at 06:17
  • (Should be `static_cast< output_trait< T >::output_type >( variable )`) – StellarVortex Nov 01 '10 at 10:14
  • @stellarvortex: Thanks, fixed. – Björn Pollex Nov 01 '10 at 10:16
  • +1 - really nice idea. **@stellavortex**: But you should still know what will be the types, that your container will have, to be able to specialize the `output_trait` for each type, as you said - "to know the type beforehand". This question is really confusing and unclear to me. And not only to me, as I see the other answers. – Kiril Kirov Nov 01 '10 at 10:33
  • 1
    Kirov, you are wrong there. Did you read Space Cowboy's note, or just the code? The template class is automatic, so all unspecialized versions will use that one. (The typedef should however be `typedef T const & output_type;` instead, to avoid copying.) – StellarVortex Nov 03 '10 at 07:09
  • What is the reason that it is not the default behaviour. After all signed char and unsigned char are listed as integer types everywhere. If answer is too big, let me know, i'll start a question. – v010dya May 12 '15 at 12:48
1

If I have understood you right.. output it like this:

std::cout << ( unsigned int )char << '\n';

Or more c++ style - use static_cast, for example:

int main()
{
    char a = 'a';
    char b = 97;
    std::cout << static_cast< unsigned int >( a ) << '\n';
    std::cout << static_cast< unsigned int >( b ) << '\n';
    return 0;
}

both std::cout will print the same: the first one - the ASCII code of 'a': 97, the second one - just the value 97, stored in b. Both, a and b, are absolutely the same.

Kiril Kirov
  • 35,473
  • 22
  • 102
  • 177
  • 10x, anyway xD It would be really nice, if posters explain themselves with examples (: – Kiril Kirov Oct 29 '10 at 07:58
  • It's not easy when you have this kind of question. It happens to all of us: if we were really able to describe with accuracy our problem, we would've already found a solution to it. I ended up answering to see if I could explain a bit further xD – slezica Oct 29 '10 at 08:03
  • Yep, you right, but what I meant was, that the poster could say: "for example, if I have stored a value `97` in an unsigned char, how to print it as the number `97`, instead of printing `a`." But you're absolutely right, this is not always possible (y) – Kiril Kirov Oct 29 '10 at 08:13
  • This is not possible from within a template operator, since it would require me to know the type beforehand. – StellarVortex Nov 01 '10 at 07:26
  • You've said: `"How do I get these other 8-bit types to **always** be output as signed int / unsigned int (numbers) instead, even when the caller doesn't know the type?"` - you don't need to know the type beforehand. As you want the output to be as `unsigned int`, you don't care what is T. Also, if such conversion is impossible (in case that the container has some user-defined type, for example, that cannot be casted to `unsinged int`), this will be a compile-time error, as templates are instantiated compile-time. – Kiril Kirov Nov 01 '10 at 09:00
  • Kiril, that would only work for unsigned non-long integers. I want my container output operator to output all types that are not 8-bit integers using their normal (or custom) output operators. – StellarVortex Nov 01 '10 at 09:54
1

You can simply cast it:

#include<iostream>

int main()
{
 uint8_t blah = 65;
 std::cout << static_cast<int>(blah) << "\n";
 return 0;
}

65

Merlyn Morgan-Graham
  • 54,918
  • 14
  • 119
  • 174
0

You can cast them before you output them:

std::cout << (unsigned int) container[index];
bjoernz
  • 3,770
  • 16
  • 29
  • container doesn't mean "string" or array, or sth. It means an object, that contains other objects/vars. So, if you have a struct with two chars inside, you can't output them like this (:. Anyway, I didn't down-vote your answer, as I understood what you mean, but don't mix the terms, please (: – Kiril Kirov Oct 29 '10 at 08:04
  • 1
    thanks for clarifying. I just tried to give a minimal, abstract example. When I started writing my answer the other (better!) answers were not there. – bjoernz Oct 29 '10 at 08:17