#include <iostream>

union Union
{
    char c;
    short s;
    int i;
    float f;
    double d;

    operator char() const { std::cout << "getting char\n"; return c; }
    operator short() const { std::cout << "getting short\n"; return s; }
    operator int() const { std::cout << "getting int\n"; return i; }
    operator float() const { std::cout << "getting float\n"; return f; }
    operator double() const { std::cout << "getting double\n"; return d; }
    template <typename T> operator T() const { std::cout << "error\n"; T t; return t; }

    Union &operator =(char ac) { c = ac; std::cout << "set char\n"; return *this; }
    Union &operator =(short as) { s = as; std::cout << "set short\n"; return *this; }
    Union &operator =(int ai) { i = ai; std::cout << "set int\n"; return *this; }
    Union &operator =(float af) { f = af; std::cout << "set float\n"; return *this; }
    Union &operator =(double ad) { d = ad; std::cout << "set double\n"; return *this; }
    template <typename T> Union &operator =(T at) { std::cout << "error!\n"; return *this; }
};

template <typename T>
void doSomething(Union a, const Union b)
{
  a = static_cast<T>(b);
}

int main(int argc, char **argv)
{
    Union a, b;
    
    doSomething<int>(a, b);
    doSomething<char>(a, b);
    doSomething<char *>(a, b);
    
    return 0;
}
