nested_exception

id:faith_and_brave:20081203 の InnerException を、nested_exception で書いてみた。

class my_nested : public exception
{
private:
    const char* what_;

public:
    my_nested(const char* what) : what_(what) { }
    virtual const char* what() const throw() { return what_; }
};

template<class T>
void output_if_exception(T e)
{
    if ((exception* ex = dynamic_cast<exception*>(e)) != nullptr)
    {
        cout << ex.what() << endl;
    }
}
try
{
    try
    {
        try
        {
            throw hoge_exception("Inner Inner Error!");
        }
        catch (...)
        {
            throw_with_nested(my_nested("Inner Error!"));
        }
    }
    catch (...)
    {
        throw_with_nested(my_nested("Error!"));
    }
}
catch (my_nested& e)
{
    output_if_exception(&e);
    try
    {
        rethrow_if_nested(e);
    }
    catch (my_nested& e2)
    {
        output_if_exception(&e2);
        try
        {
            rethrow_if_nested(e2);
        }
        catch (hoge_exception& e3)
        {
            output_if_exception(&e3);
        }
    }
}

ただ、これは catch のところで my_nested と例外を特定してしまっているので、うまく書けてない。
catch (...) で受けて、exception にキャストできるなら表示としたい場合はよく分からない。
exception_ptr が dynamic_cast 出来るなら、こんな風に直感的に書けてもいいのだけれども……

try
{
    try
    {
        try
        {
            throw hoge_exception("Inner Inner Error!");
        }
        catch (...)
        {
            throw_with_nested(my_nested("Inner Error!"));
        }
    }
    catch (...)
    {
        throw_with_nested(my_nested("Error!"));
    }
}
catch (...)
{
    output_if_exception(current_exception());
    if ((nested_exception* ne1 = dynamic_cast<nested_exception*>(current_exception())) != nullptr)
    {
        output_if_exception(ne1.nested_ptr());
        if ((nested_exception* ne2 = dynamic_cast<nested_exception*>(ne1.nested_ptr())) != nullptr)
        {
            output_if_exception(ne2.nested_ptr());
        }
    }
}

というかこっちを先に思いついたんだけど、exception_ptr って dynamic_cast できないんじゃね?と気がついて最初のやつに修正したという罠。
しかしよく考えてみると、dynamic_cast の代わりにこうやって書けそう。

template<class T>
T* dynamic_exception_cast(exception_ptr p)
{
    try
    {
        rethrow_exception(p);
    }
    catch (T& t)
    {
        return new T(t);
    }
    catch (...)
    {
        return nullptr;
    }
}
void output_if_exception(exception_ptr e)
{
    if ((exception* ex = dynamic_exception_cast<exception>(e)) != nullptr)
    {
        cout << ex.what() << endl;
    }
}
try
{
    try
    {
        try
        {
            throw hoge_exception("Inner Inner Error!");
        }
        catch (...)
        {
            throw_with_nested(my_nested("Inner Error!"));
        }
    }
    catch (...)
    {
        throw_with_nested(my_nested("Error!"));
    }
}
catch (...)
{
    output_if_exception(current_exception());
    if ((nested_exception* ne1 = dynamic_exception_cast<nested_exception>(current_exception())) != nullptr)
    {
        output_if_exception(ne1.nested_ptr());
        if ((nested_exception* ne2 = dynamic_exception_cast<nested_exception>(ne1.nested_ptr())) != nullptr)
        {
            output_if_exception(ne2.nested_ptr());
        }
    }
}

当然 new してるからリークするけど、うまくすればもう少し綺麗に書けるんじゃないかなーと思ったり。