2016-03-11 2 views
3

Je suis en train d'écrire un manipulateur personnalisé I/O en C++ qui peuvent écrire bien formaté hexadécimaux sous la forme 0xFFFF en fonction de la taille de l'entier fourni.C++ personnalisé manipulateur d'E/S pour les entiers hexadécimaux

Par exemple:

  • char c = 1 devient 0x01
  • short s = 1 devient 0x0001

Et ainsi de suite. Vous ne trouvez pas l'erreur dans mon code, qui est l'impression des ordures:

#include <iostream> 
#include <iomanip> 


class hexa_s 
{ 
    mutable std::ostream *_out; 

    template<typename T> 
    const hexa_s& operator << (const T & data) const 
    { 
     *_out << std::internal << std::setfill('0') << std::hex << std::showbase << std::setw(sizeof(T) * 2) << data; 

     return *this; 
    } 

    friend const hexa_s& operator <<(std::ostream& out, const hexa_s& b) 
    { 
     b._out = &out; 
     return b; 
    } 
}; 

hexa_s hexa() 
{ 
    return hexa_s(); 
} 


int main() 
{ 
    int value = 4; 

    std::cout << hexa << value << std::endl; 

    return 0; 
} 
+0

Il devrait être soit 'sizeof (T) * CHAR_BIT/4', ou mieux encore,' std :: numeric_limits :: chiffres()/4' (peut-être avec un arrondi approprié). –

Répondre

3

Cette ligne

std::cout << hexa << value << std::endl; 

écrit un pointeur (à la fonction hexa). La fonction devrait être appelée.

+0

c'est sûr une des erreurs merci, mais il semble que ce n'est pas le seul. Il semble que maintenant il ne peut pas streamer 'std :: endl' après' hexa() << value' – nyarlathotep108

+0

'ami const hexa_s & operator << (std :: ostream & out, const hexa_s & b)' devrait retourner la référence à 'std :: ostream', pas la référence à 'hexa_s' – user4581301

1

Ce n'est en aucun cas une critique. Il me semble que l'écriture d'un manipulateur io n'est pas un petit travail. Il y a beaucoup de «what-if» et de «gotcha».

Je pourrais avoir choisi de le faire de cette façon. Qu'est-ce que tu penses?

#include <iostream> 
#include <utility> 
#include <limits> 
#include <iomanip> 


// in the general case, return a value unchanged 
template<class Integral> auto as_integer(Integral i) { return i; } 

// but in the case of chars, we must convert them to integers 
// otherwise operator<< treats them as characters and does not 
// obey the hex iomanipulator 
auto as_integer(char c) { return int(c) & 0xff; } 
auto as_integer(unsigned char c) { return unsigned(c) & 0xff; } 

// This is a basic hex printer for any integral 
template<typename Integral> 
struct hex_printer 
{ 
    static constexpr size_t hex_digits = sizeof(Integral) * 2; 

    hex_printer(Integral i) : _i(i) {} 

    std::ostream& operator()(std::ostream& os) const 
    { 
     auto flags = os.flags(); 
     try { 
      os << std::setfill('0') << std::setw(hex_digits) << std::hex << as_integer(_i); 
     } 
     catch(...) { 
      os.flags(flags); 
      throw; 
     } 
     os.flags(flags); 
     return os; 
    } 

    Integral _i; 
}; 


template<typename Integral> 
inline std::ostream& operator<<(std::ostream& os, hex_printer<Integral> const& hp) 
{ 
    return hp(os); 
} 

template<typename Integral> 
auto neat_hex(Integral i) { 
    return hex_printer<std::decay_t<Integral>>(i); 
} 

int main() 
{ 
    int x= 0xf045; 
    short y = 0x6fa; 
    std::int64_t z = 0xe32; 
    std::uint8_t w = 0xde; 

    using namespace std; 
    cout << neat_hex(x) << " " << neat_hex(y) << " " << neat_hex(z) << " " << neat_hex(w) << endl; 
    return 0; 
} 

exemple sortie:

0000f045 06fa 0000000000000e32 de 
+0

Je suis d'accord, ce n'est pas un petit travail. A propos de votre code, pour moi cela ne fonctionne pas avec 'std :: int8_t'. Une autre petite chose, pensez-vous qu'il est possible de le faire fonctionner comme l'autre 'std'' 'sans' operator() 'mais en utilisant simplement les opérateurs de streaming comme' std :: cout << neat_hex << value << std :: endl'? – nyarlathotep108

+1

Uint8 est un caractère ainsi émis et un caractère. Vous devrez fournir une spécialisation pour Uint8 qui le convertira en int avant le streaming dans l'objet fonction –

+1

C'est probablement possible mais très difficile. Vous ne pouvez pas prédire ce qui va apparaître sur le côté droit de votre manipulateur –