dlaczego dla typów wbudowanych możemy dać unsigned a dla własnych nie
Dlatego, że unsigned jest częścią (nazwy) typu, a nie jego modyfikatorem (jak na przykład const lub volatile).
unsigned val1; // typ val1 to "unsigned int"
unsigned std::string val2; // błąd, nie istnieje taki typ
Poza tym nie dla wszystkich typów fundamentalnych można używać nazw signed/unsigned:
unsigned float val1; // nie
signed std::nullptr_t val2; // też nie
using uvoid_t = unsigned void; // huh?