La tua espressione regolare non è corretta perché nessuno dei due gruppi Capture esegue ciò che desideri. Il primo sta cercando di abbinare un singolo carattere dal set [a-zA-Z0-9] seguito da <space>: , che funziona per nomi utente a carattere singolo, ma nient'altro. Il secondo gruppo di acquisizione sarà sempre vuoto perché stai cercando zero o più caratteri, ma anche specificare la corrispondenza non dovrebbe essere avido, il che significa che una corrispondenza di zero caratteri è un risultato valido.
 Correggere entrambi i tuoi regex diventa
std::regex rgx("WEBMSG #([a-zA-Z0-9]+) :(.*)");
 
 Ma semplicemente istanziando un regex e un match_results oggetto non produce corrispondenze, è necessario applicare un regex algoritmo. Dal momento che vuoi solo corrispondere a parte della stringa di input, l'algoritmo appropriato da utilizzare in questo caso è regex_search .
std::regex_search(s, matches, rgx);
 Mettere tutto insieme
    std::string s{R"(
tХB:[email protected] Connected
tХB:[email protected] WEBMSG #Username :this is a message
tХB:[email protected] Status: visible
)"};
    std::regex rgx("WEBMSG #([a-zA-Z0-9]+) :(.*)");
    std::smatch matches;
    if(std::regex_search(s, matches, rgx)) {
        std::cout << "Match found\n";
        for (size_t i = 0; i < matches.size(); ++i) {
            std::cout << i << ": '" << matches[i].str() << "'\n";
        }
    } else {
        std::cout << "Match not found\n";
    }
 Dimostrazione dal vivo
"WEBMSG #([a-zA-Z0-9]) :(.*?)"
 Questa regex corrisponderà solo alle stringhe, che contengono un nome utente di 1 carattere e qualsiasi messaggio dopo il punto e virgola, ma il secondo gruppo sarà sempre vuoto, perché cerca di trovare la corrispondenza meno avida di qualsiasi carattere da 0 a illimitato.
Dovrebbe funzionare:
"WEBMSG #([a-zA-Z0-9]+) :(.*)"