Egor Tensin
Egor Tensin

Reputation: 608

Inherit custom exception class from both boost::exception and std::runtime_error

I would like to introduce a hierarchy of my custom exception classes, derived both from boost::exception and std::runtime_error so that what() returns something meaningful.

So far I had no luck:

#include <iostream>
#include <stdexcept>

#include <boost/exception/all.hpp>

typedef boost::error_info<struct tag_foo_info, unsigned long> foo_info;

struct foo_error : virtual boost::exception, virtual std::runtime_error
{
  explicit foo_error(const char *const what)
    : std::runtime_error(what)
  { }
};

static void foo()
{
  BOOST_THROW_EXCEPTION(foo_error("foo error") << foo_info(100500));
}

int main(int argc, char *argv[])
{
  try
  {
    foo();
  }
  catch (const std::exception& e)
  {
    std::cerr << boost::diagnostic_information(e);
    return 1;
  }

  return 0;
}

just keeps complaining that there are no appropriate default constructor available for std::runtime_error.

The closest I can get is to throw an actual std::runtime_error using

BOOST_THROW_EXCEPTION(boost::enable_error_info(std::runtime_error("foo error")) << foo_info(100500)))

but that's not really what I want. Basically, I want an exception class being catchable by catch (const std::exception& e), catch (const std::runtime_error& e), catch (const boost::exception& e) and catch (const foo_error& e). Is that possible? Thank you in advance.

Upvotes: 1

Views: 1289

Answers (2)

user2249683
user2249683

Reputation:

You need public inheritance

struct Exception : public boost::exception, public std::runtime_error
{
    Exception()
    :   std::runtime_error("Hello World")
    {}
};

int main()
{
    try {
        try {
            throw Exception();
        }
        catch(const std::runtime_error&) {
            std::cout << "std::runtime_error" << std::endl;
            throw;
        }
    }
    catch(const boost::exception&) {
        std::cout << "boost::exceptionr" << std::endl;
    }
    return 0;
}

Your code will work if you replace the two virtual:

Throw in function void foo()
Dynamic exception type: boost::exception_detail::clone_impl<foo_error>
std::exception::what: foo error
[tag_foo_info*] = 100500

The boost exception library has a class deriving from your exception:

// Curiously recurring template pattern (exception.hpp:419:20)
class clone_impl: public Exception, public clone_base;

Due to virtual inheritance the most derived class is responsible to initialize the base classes (clone_impl does not)

Upvotes: 4

greken
greken

Reputation: 89

std::runtime_error already inherits from std::exception. So you only need inherit std::runtime_error and you'll get both.

UPDATE: I meant inheriting only std::runtime_error. What if you try this:

#include <iostream>
#include <stdexcept>

struct foo_error : public std::runtime_error
{
    explicit foo_error(const char *const what)
        : std::runtime_error(what)
    { }
};

static void foo()
{
    throw foo_error("foo error");
}

int main(int argc, char *argv[])
{
    try
    {
        foo();
    }
    catch (const std::exception& e)
    {
        std::cerr << boost::diagnostic_information(e);
        return 1;
    }
    return 0;
}

left out the boost stuff for simplicity.

Upvotes: -1

Related Questions