Consider this 2 exception outputs.
===== case A =====
terminate called after throwing an instance of 'network_error'
what(): connection failed (104).
===== case B =====
terminate called after throwing an instance of 'network_error'
what(): conection failed (with layer = transport, protocol = tcp, local_endpoint =
0.0.0.0:21798, remote_endpoint =
198.23.64.125:37720, error_code = 104, reason = "Connection reset by peer", status = "SYN ACK")
In user's perspective, the user/caller usually prefers an output like B. But currently almost all C++ 3rd-party libraries (who use exception rather then error_code/assert) provides something like A.
Maybe should we **encourage** people to carry more information in exceptions?
For case B you are much better off capturing the data in the exception object directly, not formatting it as a string.
i.e. instead of:
throw network_error("connection failed (with layer = {}, protocol = {}, local_endpoint = {}, remote_endpoint = {}, error_code = {}, reason = \"{}\", status = \"{}\"", layer, proto, lep, rep, ec, why, status);
you should do:
throw network_error("connection failed", layer, proto, lep, rep, ec, why, status);
The exception type should store those values and provide getters to access those values later. It can also use std::format internally to create a string that is stored and returned from network_error::what() (maybe by passing that string to a std::runtime_error base class, if it derives from that).