#include <boost/optional.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/mpl/if.hpp>
#include <cassert>

using namespace boost;

//
// callable/as_callable -- a lightweight substitute for
// boost::function0<void>; we don't need to copy the function object.
// Could go further and use the boost::function trick to eliminate
// virtual function bloat.
//
struct callable
{
    virtual void operator()() const = 0;
};

template <class F>
struct as_callable : callable
{
    as_callable( F f ) // implicit conversion from anything
      : f( f ) {}
    
    void operator()() const
    {
        f();
    }

    F& f;
};

//
// A base class for nodes in the doubly-linked chain of individual
// handlers that translate exceptions into objects of type Error.
//
template <class Error = void>
class handler_node : noncopyable
{
 public:
    // Unlink from the chain.
    virtual ~handler_node()
    {
        next->prev = this->prev;
        prev->next = this->next;
    }
    
 protected:
    // Construct a doubly self-linked starter node
    handler_node()
      : prev( this )
      , next( this )
    {}
    
    // Construct and insert this node after chain
    handler_node( handler_node& chain )
      : prev( &chain )
      , next( chain.next )
    {
        chain.next->prev = this;
        chain.next = this;
    }

    // Call f in the context of the next handler.
    void
    try_nested( callable const& f, optional<Error>& e ) const
    {
        assert( this->next != this );
        return this->next->try_( f, e );
    }
    
 private:
    // Call f within the context of this and all following handlers.
    // If an exception is handled, e will be assigned from the result
    // of the handler.  Otherwise, the thrown exception propagates.
    virtual void
    try_( callable const& f, optional<Error>& e ) const = 0;

 private: // data members
    handler_node* prev;
    handler_node* next;
};

//
// The "starter node" for a doubly-linked list of handler_nodes.  
//
template <class Error = void>
class handler_set
  : public handler_node<Error>
{
 public:
    
    // Call f in the context of all handlers on this chain.  If no
    // exception is thrown, the result is empty.  Otherwise, if an
    // exception was handled the result is constructed from the result
    // of the handler.  Otherwise, the thrown exception propagates.
    template <class F>
    optional<Error> operator()( F& f ) const
    {
        optional<Error> e;
        this->try_nested( as_callable<F>( f ), e );
        return e;
    }
            
    template <class F>
    optional<Error> operator()( F const& f ) const
    {
        optional<Error> e;
        this->try_nested( as_callable<F const>( f ), e );
        return e;
    }
    // ------ //
    
    handler_set() {}

 private:
    virtual void
    try_( callable const& f, optional<Error>& ) const
    {
        // This is always the last node tried in any chain; we can
        // invoke f here.
        f();
    }
};

#include <boost/type_traits/remove_reference.hpp>

// A CRTP base class for exception handlers
template <
    class Derived
  , class Error = void
>
class exception_handler
  : public handler_node<Error>
{
 protected:
    exception_handler() {}
    
    exception_handler( handler_set<Error>& chain )
      : handler_node<Error>( chain )
    {}
    
    typedef exception_handler base;

 private:
    // handler_node override
    void
    try_( callable const& f, optional<Error>& e ) const
    {
        // To avoid having to specify the exception type as a template
        // parameter here, pass a pointer to the catch_ function and
        // allow the exception type to be deduced.
        return this->try_impl( &Derived::catch_, f, e );
    }

    template <class R, class X>
    void
    try_impl(
        R (Derived::*)(X) const
      , callable const& f
      , optional<Error>& e
    ) const
    {
        try
        {
            this->try_nested( f, e );
        }
        catch( X x ) // Now that X is deduced, we can catch it.
        {
            // But don't use that member function pointer; we can call
            // the catch_ function directly.
            e = static_cast<Derived const*>( this )->catch_( x );
        }
    }
    
};

//
// Test code
//

handler_set<std::string> translate;

#include <exception>
struct std_handler
  : exception_handler<std_handler, std::string>
{
    std_handler() : base( translate ) {}
    
    std::string catch_( std::exception const& e ) const
    {
        return std::string( e.what() );
    }
} h1;

#include <boost/lexical_cast.hpp>
struct int_handler
  : exception_handler<int_handler, std::string>
{
    int_handler() : base( translate ) {}
    
    std::string catch_( int n ) const
    {
        return boost::lexical_cast<std::string>( n );
    }
} h2;


#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>
#include <boost/lambda/exceptions.hpp>
#include <iostream>
#include <memory>

int main()
{
    using namespace boost::lambda;
    
    if (
        optional<std::string> msg = translate(
            lambda::throw_exception( std::bad_alloc() )
        ) )
    {
        std::cout << *msg << std::endl;
    }
    
    if (
        optional<std::string> msg = translate(
            lambda::throw_exception( 42 )
        ) )
    {
        std::cout << *msg << std::endl;
    }

    // This one doesn't throw
    if (
        optional<std::string> x = translate(
            lambda::constant( "foobar" )
        )
    )
    {
        std::cout << "unexpected error: " << *x << std::endl;
    }
}

