Context
While reviewing #33657 it became clear we don’t have a good value-or-error wrapper, similar in spirit to std::expected<T, E> in C++23.
Problem
The util::Result helper currently stores a std::variant<bilingual_str, T> and is effectively only usable for high-level code that needs to propagate user-facing error strings.
Low-level code that wants typed error codes instead of strings still has to expose raw std::variant (or roll custom structs).
Fix
Generalize util::Result to take a second template parameter E for the error type, and store std::variant<E, T> internally.
The default E remains bilingual_str, so existing uses of Result<T> and util::Error{...} behave exactly as before and ErrorString(Result<T>) continues to work.
New code can now use typed errors and avoid the awkward std::variant getter, e.g.:
0if (auto ret{chainman->m_blockman.ReadRawBlock(WITH_LOCK(cs_main, return index.GetBlockPos()))}) {
1 block = std::move(*ret);
2 return true;
3}
4return false;