That's actually a very good question, as things stand, I think the only way you can know what the caller is, is to check the string name passed to the error handler. It is possibly "worse" than that too as some special functions can call other special functions internally, so in a few rare cases, if something has gone badly wrong in the "outer" function, the actual error may be generated in the "inner" function :(
But leaving aside that issue for the moment, I would probably create a sorted table of std::pair
, with the first member of the pair being our name, the second your name, and then do a std:::lower_bound to find a matching entry and do the name translation. I don't think our names have ever changed, so while we've never guaranteed stability of those, it's hard to imagine them changing unless someone spots a really grievous spelling mistake or something ;) You would still need to perform the rather tedious job of calling each function you're wrapping with say NaN parameters, and then logging the string name of the function in the error handler so you know what to put in the table.
Maybe we're both over-thinking this, why not just: double erfinv_double(double x) { try{ return erf_inv(x, special_policy()); } catch(const std::domain_error&) { // Python error handling here. } catch(whatever-else-may-get-thrown){ /*more error handling*/} } ?