I'm trying to design a custom exception hierarchy. What I want is, to inherit from standard exceptions and errors as much as possible, to allow catching custom exceptions in the case of catching STL ones.
For instance, in the following hierachy, if you catch an instance of std::logic_error
, then an instance of LogicException
will also be caught:
-> Exception --> LogicException
/ ^
std::exception --> std::logic_error --^
So, this is the code to achieve this (excluding header guard, includes and namespace scopes, and definitions):
class Exception: public std::exception
{
public:
Exception() = delete;
Exception(const char *) noexcept(true);
Exception(const std::string &) noexcept(true);
virtual Message what() const noexcept(true);
private:
std::string message;
};
class LogicException: public Exception, public std::logic_error
{
public:
LogicException() = delete;
using Exception::Exception;
using Exception::what;
};
However, considering the following basic main function (again, excluding non-sense parts):
int main()
{
throw LogicException("Oops!");
}
I'll get the following error (compiling with GCC 10.0.1):
test.cpp: In function ‘int main()’:
test.cpp:5:29: error: use of deleted function ‘LogicException::LogicException(const char*) [inherited from Exception]’
5 | throw LogicException("e");
| ^
In file included from test.cpp:1:
./include/exception.hpp:27:34: note: ‘LogicException::LogicException(const char*) [inherited from Exception]’ is implicitly deleted because the default definition would be ill-formed:
27 | using Exception::Exception;
| ^~~~~~~~~
./include/exception.hpp:27:34: error: no matching function for call to ‘std::logic_error::logic_error()’
In file included from ./include/exception.hpp:4,
from test.cpp:1:
/usr/include/c++/10/stdexcept:131:5: note: candidate: ‘std::logic_error::logic_error(const std::logic_error&)’
131 | logic_error(const logic_error&) _GLIBCXX_NOTHROW;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:131:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:126:5: note: candidate: ‘std::logic_error::logic_error(std::logic_error&&)’
126 | logic_error(logic_error&&) noexcept;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:126:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:124:5: note: candidate: ‘std::logic_error::logic_error(const char*)’
124 | logic_error(const char*) _GLIBCXX_TXN_SAFE;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:124:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:120:5: note: candidate: ‘std::logic_error::logic_error(const string&)’
120 | logic_error(const string& __arg) _GLIBCXX_TXN_SAFE;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:120:5: note: candidate expects 1 argument, 0 provided
So, the questions are:
After a while, I think this is why the error occurs: While using
Exception
constructor, the compiler tries to implicitly call the (default) constructor ofstd::logic_error
, which does not exist. Is that true?Is there any way to prevent this error (e.g. somehow calling
std::logic_error
's constructor explicitly) without having to explicitly declareLogicException
constructor or changing class hierarchy?Note: The reason I don't want to explicitly declare
LogicException::LogicException
is that I'd have some exception classes defined this way, thus, I don't want to add extra files definingLogicException
class or whatever.Generally speaking, is using the above idea in designing exceptions good?
Thanks.