#include <iostream>
#include <print>
#include <typeinfo>
#include <cstring>

// Funktionstemplate zur byteweisen 'Übertragung' eines
// Wertes in ASCII-Form
template <typename T>
void SendTo(std::ostream& os, T value)
{
    // Datentyp ausgeben
    os << typeid(T).name() << ' ';
    // char-Zeiger auf Datenbeginn aufsetzen
    const char* p = reinterpret_cast<const char*>(&value);
    // Alle Bytes durchlaufen
    for (size_t i=0; i<sizeof(T); i++)
    {
        // Low-Nibble nach ASCII konvertieren
        char lowNibble = (*p)&0x0f;
        lowNibble = (lowNibble>9) ? lowNibble+0x57 : lowNibble|0x30;
        // High-Nibble nach ASCII konvertieren
        char highNibble = ((*p)>>4)&0x0f;
        highNibble = (highNibble>9) ? highNibble+0x57 : highNibble|0x30;
        // Datum in ASCII-Form 'übertragen'
        os << highNibble << lowNibble << ' ';
        // Zeiger auf nächstes Byte
        p++;
    }
    os << '\n';
}

// Spezialisiertes Funktionstemplate zur byteweisen 'Uebertragung'
// eines C-Strings in ASCII-Form
template <>
void SendTo<const char*>(std::ostream& os, const char* value)
{
    // Datentyp ausgeben
    os << typeid(value).name() << ' ';
    // Alle Bytes durchlaufen
    const char* p = value;
    for (size_t i = 0; i < std::strlen(value); i++)
    {
        // Datum in ASCII-Form 'übertragen'
        os << *p << ' ';
        // Zeiger auf nächstes Byte
        p++;
    }
    os << '\n';
}
// main() Funktion
int main()
{
    // Auszugebende Daten
    int intVal = 10;
    char charVal = 'A'; // entspricht 'A'

    // Aufruf der Template-Funktion
    // Der Template-Datentyp ergibt sich aus dem Datentyp des Parameters
    std::print("sending {} as bytes: ", intVal);
    SendTo(std::cout,intVal);
    std::print("sending {} as bytes: ", charVal);
    SendTo(std::cout,charVal);

    // Aufruf der Template-Funktion mit Literalen
    // Standardmässig werden Literale als ints behandelt
    // Soll SendTo() mit anderem Datentyp aufgerufen werden,
    // so kann entweder der Datentyp explizit festgelegt werden
    // (2. Aufruf) oder aber der Template-Datentyp explizit
    // angegeben werden (3. + 4. Aufruf)
    std::print("sending {} as bytes: ", 0x61);
    SendTo(std::cout,0x61);
    std::print("sending {}L as bytes: ", 0x61L);
    SendTo(std::cout,0x61L);
    std::print("sending char {} as bytes: ", 0x61);
    SendTo<char>(std::cout,0x61);
    std::print("sending short {} as bytes: ", 0x1234);
    SendTo<short>(std::cout,0x1234);
    auto text = "Ein Text";
    std::print("sending C-String {} as bytes: ", text);
    SendTo(std::cout,text);
}
