You cannot overload the throw operator. The more usual solution would be to define a macro that packages the exception with a backtrace record. For example this:
#include <string>
#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <type_traits>
template <typename BaseException>
class backtraced_exception : public BaseException {
private:
std::string backtrace;
public:
template <typename... Args>
backtraced_exception(const char* aFilename, int aLineNum, Args&&... args) :
BaseException(std::forward<Args>(args)...) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< BaseException::what();
backtrace = ss.str();
};
backtraced_exception(const std::exception& e, const char* aFilename, int aLineNum) :
BaseException(static_cast<const BaseException&>(e)) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< e.what();
backtrace = ss.str();
};
virtual ~backtraced_exception() noexcept { };
virtual const char* what() const noexcept {
return backtrace.c_str();
};
};
#define THROW_WITH_BACKTRACE(EXCEPTION, ARG1) throw backtraced_exception< EXCEPTION >(__FILE__, __LINE__, ARG1)
// ... and you can create more macros for more arguments...
#define CATCH_WITH_BACKTRACE(EXCEPTION, EXCEPT_NAME) catch(backtraced_exception< EXCEPTION >& EXCEPT_NAME)
#define RETHROW_WITH_BACKTRACE(EXCEPT_NAME) throw backtraced_exception< std::decay< decltype(EXCEPT_NAME) >::type >(EXCEPT_NAME, __FILE__, __LINE__)
Use it like this:
int main() {
try {
try {
try {
THROW_WITH_BACKTRACE(std::runtime_error, "This is an example!");
} CATCH_WITH_BACKTRACE(std::runtime_error, e) {
std::cout << "First caught this exception:\n" << e.what() << std::endl;
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) { // can also catch normally.
std::cout << "Got this exception:\n"
<< e.what() << std::endl;
// and even rethrow again, with backtrace:
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) {
std::cout << "Finally, got this exception:\n"
<< e.what() << std::endl;
};
};
The output is as follows:
First caught this exception:
From 'logged_except.cpp' at line 50:
This is an example!
Got this exception:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
Finally, got this exception:
From 'logged_except.cpp' at line 59:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
Another good thing with this solution is that you can disable backtracing by simply conditionally defining the macros depending on whether you want backtracing or not (e.g. debug or release build).
The above example requires C++11 features, but you can probably come up with an equivalent solution without those features (i.e., variadic templates, decltype, type-traits, etc.).
And you could also use C++11 exception-pointers to make this scheme even more convenient.